React - Practice Router, useNavigate, useEffect through Carrot page

화이티 ·2023년 12월 18일
0

react

목록 보기
5/11


Plan

  1. 라우트 구성
  • / : Main.jsx
  • /list : ProductList.jsx
  • /detail : ProductDetail.jsx

** Header와 Footer 는 라우트에 영향을 받지 않는다.

  1. 메인 구성
  • 자율
  1. Header 구성
  • 카톡 참조
  1. List 구성
    1) public 에 있는 bestList.json 파일을 가져올 거임 (axios 로)
    2) 가져온 데이터로 화면을 세팅 (map 함수)
  • ProductItem 으로
  • 내가 필요한 것들은 props로 전달
  1. 내가 클릭한 요소에 따라 다른 ProductDetail을 뽑아 줄 것
  • useParams 를 사용 할 거임

Process

1. App.js

import { Routes, Route } from 'react-router-dom';
import './App.css';
import Main from './components/Main';
import ProductList from './components/ProductList';
import ProductItem from './components/ProductItem';
import ProductDetail from './components/ProductDetail';
import Header from './components/Header';
import Footer from './components/Footer';
import { BrowserRouter as Router} from 'react-router-dom';
import { useState } from 'react';
function App() {
 

const [list, setList]= useState([]);
  return (
   
    <div className='container'>
    <Header/>
    
     <Routes>
        <Route path='/' element={<Main/>}></Route>
        <Route path ='/list' element = {<ProductList list ={list} setList={setList}/>}/>
        <Route path ='/detail/:num' element = {<ProductDetail/>}/>
      
     </Routes>

    <Footer/>
    </div>
  
  );
}

export default App;

2. App.css

*{
  margin: 0;
  padding: 0;
}

.container{
  height : 100vh;
  width: 100vw;
  display: block;
}

.container>div{
  display: flex;
  align-items: center;  
}
.header-container{
  background-color: lightgray;
  height: 10vh;
  justify-content: space-between;
  font-size: 1.5em;
  font-weight: bolder;
  padding: 0 5vw;
}

.header-container>a{
  color: black;
  text-decoration: none;
}

.footer-container{
  background-color: lightgray;
  height: 10vh;
  justify-content: center;
}

.main-container{
  /* background-color: #FFFAE0; */
  height: 80vh;
  
  padding: 0 5vw;
  box-sizing: border-box;
  
  overflow: auto;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-evenly;
}

.main-container>.main-text{
  width: 45vw;
  font-size: 1.75rem;
}
.main-container>.main-image{
  width: 45vw;
  display: flex;
  justify-content: right;
}
.main-container>.main-image>img{
  height: 70vh;
}

.product-container{
  background-color: lightyellow;
  margin: 2.5vh 0;
  height: 75vh;
  border-radius: 20px;
  font-size: 1.75rem;

  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

  padding: 3vw;
  box-sizing: border-box;
  /* overflow: hidden; */
  transition: 0.5s;
}

.product-container img{
  width: 30vw;
}

.product-container:hover{
  box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.1);
}

.detail-text>p{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.detail-container{
  flex-direction: row;
  width: 70vw;
}
.detail-image{
  display: flex;
  align-items: center;
}
.detail-text{
  margin-left: 3vw;
}

3. Folder public -> bestList.json (to send data)

{
    "list": [
        {
            "no" : 1,
            "title": "딸기 레터링 케이크 캔들 +머리띠🍓",
            "price": 18900,
            "delivery": "free",
            "src": "https://image.idus.com/image/files/7ad7fcd0400d40319630e1520cac6119_1440.jpg"
        },
        {
            "no" : 2,
            "title": "위피베어 침구세트-프리지아",
            "price": 18000,
            "delivery": "3000",
            "src": "https://image.idus.com/image/files/994385ec40fd4ed8aa41381d78456b02_1440.jpg"
        },
        {
            "no" : 3,
            "title": "도화 비녀/한복 머리 장식/뒤꽂이",
            "price": 16910,
            "delivery": "free",
            "src": "https://image.idus.com/image/files/35e0882e95bd4f75bc14e70707b11029_1440.jpg"
        },
        {
            "no" : 4,
            "title": "미니미 꼬질곰 뜨개 인형 키링🧸💖",
            "price": 10100,
            "delivery": "3000",
            "src": "https://image.idus.com/image/files/93d923d7167e4a428a9771520ddda4cf_1440.jpg"
        },
        {
            "no" : 5,
            "title": "꽃에 취한냥🌸주병 선물세트",
            "price": 43000,
            "delivery": "3000",
            "src": "https://image.idus.com/image/files/0d8bdf6b191541e88cdc42892bc7ca23_1440.jpg"
        },
        {
            "no" : 6,
            "title": "납작뜨개키링",
            "price": 12000,
            "delivery": "3000",
            "src": "https://image.idus.com/image/files/63b018f447bb46018941598c1b219d6a_1440.jpg"
        }
    ]
}

4. Folder components -> Create

4.1 Footer.jsx

import React from 'react'

const Footer = () => {
  return (
    <div className='footer-container'>
      <strong>전화</strong>1544-9796<br></br>
      <strong>고객문의</strong>css@carrot.service.com
    </div>
  )
}

export default Footer

4.2 Header.jsx

import React from 'react'
import {Link, useNavigate} from 'react-router-dom'
const Header = () => {
  const nav = useNavigate();
  let auth = true;
  
    return (
      <div className='header-container'>
        <Link to ='/'> 당근마켓 </Link>
       <Link to ='/list'> 상품목록</Link>
       
         
      </div>
    )
}

export default Header

4.3 Main.jsx

import React from 'react'

const Main = () => {
  return (
    <div className='main-container'>
<div className='main-text'>
  <h1>당신 근처의 지역 생활 커뮤니티</h1>
<p>동네라서 가능한 모든 것</p><br></br>
<p>당근에서 가까운 이웃과 함께해요.</p>




 
</div>
<div className='main-image'><img src ="https://d1unjqcospf8gs.cloudfront.net/assets/home/main/3x/rebranded-image-top-eb44f81acb1938b57ba029196887cdd56fbb66dc46aa5d8c6d8392a7d8c9e671.png" alt = ""></img></div>

    </div>
  )
}

export default Main

4.4 ProductDetail.jsx

import React from 'react'
import { useParams, useSearchParams } from 'react-router-dom'
const ProductDetail = ({list}) => {
  let {num} = useParams();
console.log(list[num]);

  return (
    <div className='main-container'>
<div className='product-container detail-container'>
<div className='detail-image'>
  <img src = {list[num].src} alt = ""></img>
</div>
<div className='detail-text'></div>
<h4>{list[num].title}</h4>
<p>
<span>
 Price: {list[num].price} 원
</span><br></br>
<span>
 Delivery: {list[num].delivery ==='free'? '무료배송':'배송비'+list[num].delivery+'원'}
</span>
</p>
</div>
    </div>
  )
}

export default ProductDetail

4.5 ProductItem.jsx

import React from 'react'
import { useNavigate } from 'react-router-dom';

const ProductItem = ({item, index}) => {
  console.log('test', item, index);
  /*
  해당 아이템 div을 클릭했을 때,
  아이템에 대한 상세페이지(ProductDetail)로 이동
  => useNavigate 사용
  => 상품별 고유번호 index 사용 : /detail/1, /detail/2
  */
 const nav = useNavigate();
  return (
    <div className='product-container'
    onClick={()=>{nav(`/detail/${index}`)}}>
      <img src={item.src}/>
      <p>{item.title}</p>
      <p>{item.price}원</p>
    </div>
  )
}

export default ProductItem

4.6 ProductList.jsx

import React from 'react'
import { useParams, useSearchParams } from 'react-router-dom'
import ProductItem from './ProductItem'
import Header from './Header'
import Footer from './Footer'
import ProductDetail from './ProductDetail'
import { useEffect } from 'react'
import axios from 'axios'

const ProductList = ({list, setList}) => {
  /*
  (1) public 안 bestList.json데이터 접근
  => axios, useEffect 이용
  (2)가지고 온 데이터 list에 세팅

  */ 
  
  useEffect(()=>{
   axios
   .get("http://localhost:3000/bestList.json")
   .then((res)=>{
    console.log(res.data.list);
    setList(res.data.list)
   })
   .catch()
//api data를 주고 받을 수 있는 문볍 2가지: fetch,axios
// case 1: fetch API
// - 장점: js잦체 내장 라이버라리, 별도의 설치 필요없고 속도가 상대적으로 빠름
//- 단점: 가끔 지원이 되지 않은 브라우저 => 그러다 보니 react-native (어플)에서 많이 사용
//        json변환 작업 필요
 
   
 },[])
  return (
    <>
   
    <table>
      <tbody>
       
            {
            list.map((item,index)=>(
              
               
                <ProductItem key ={item.no} item ={item} index = {index}/>
               
            ))
        }
        </tbody>
     </table>
   
    
    </>
  )
}

export default ProductList
profile
열심히 공부합시다! The best is yet to come! 💜

0개의 댓글