React # 11 라우트 실습

장서영·2023년 12월 20일
0

React

목록 보기
11/12

라우트 실습1

상품 목록페이지에서 상품을 누르면 상품 상세 정보 페이지

메인 창

상품목록 페이지

상품을 누르면

상품 상세 페이지가 뜸

App.js

import logo from './logo.svg';
import './App.css';
import Header from './components/Header';
import Footer from './components/Footer';
import { Routes,Route } from 'react-router-dom';
import Main from './components/Main';
import ProductDetail from './components/ProductDetail';
import ProductList from './components/ProductList';
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>
        <Route path='/detail/:num' element={<ProductDetail list={list}/>}> 메인</Route>
      </Routes>
      <Footer/>
      
    </div>
  );
}

export default App;

ProductList에 list와 setList값,
ProductDetail에는 list값 넘겨주기

Header.jsx

import React from 'react'
import { Link } from 'react-router-dom'

const Header = () => {
  return (
    <div className='header-container'>
      <Link to='/'>Kream 👓</Link>
      <Link to='/list'>상품목록 </Link>
      
    </div>
  )
}

export default Header

Footer.jsx

import React from 'react'

const Footer = () => {
  return (
    <div className='footer-container'>
      <strong>크림 주식회사</strong> · 대표 김창욱사업자등록번호 : 570-88-01618 
    </div>
  )
}

export default Footer

Main.jsx

import React from 'react'

const Main = () => {
  return (
    <div className='main-container'>
      <div className='main-text'>
      <h1>
        한정판 거래 플랫폼, KREAM
      </h1>
      </div>

      <div className='main-image'>
        <img src="https://cloudfront-ap-northeast-1.images.arcpublishing.com/chosunbiz/IVMTVZH5PBBABK627VRILTVTMY.jpg" />
      </div>
      
    </div>
  )
}

export default Main

ProductList.jsx

import React, { useEffect } from 'react'
import axios from 'axios'
import ProductItem from './ProductItem'

const ProductList = ({list,setList}) => {

  /*
  (1) public 안 bestList.json 데이터 접근
      => axios, useEffect이용
  (2) 가지고 온 데이터 list에 세팅
  => useNavigate 사용
  => 상품별 고유번호 index 사용 : /detail/1, detail1/2
  */

  useEffect(()=>{
    axios
    .get('http://localhost:3000/bestList.json')
    .then(res=>{
      console.log(res.data.list);
      setList(res.data.list)})
  },[])

  console.log("list",list);

  return (
    <div className='main-container'>
      {list.map((item,index)=>
        <ProductItem key={index} item={item} index={index}/>
      )}

    <div onClick={()=>{
      
    }}></div>
    </div>

    
    
  )
}

export default ProductList

**첫 렌더링 때 axios 이용하여 public 파일에 json파일 가져오기!!

list를 map으로 돌리면서 ProductItem에 list정보 props로 넘겨주기**

ProductItem.jsx

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

const ProductItem = ({item,index}) => {
  console.log(item,index);
  /*
  해당 아이템 div을 클릭 했을 때,
  아이템에 대한 상세페이지(ProductDetail)로 이동
  */

  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

list값(item,index) props로 가져옴
naviate-> 조건을 걸 수 있다
클릭시 해당 상품 상세 정보 페이지로 넘어감

ProductDetail.jsx

import React from 'react'
import { Link, useNavigate, useParams } from 'react-router-dom'

const ProductDetail = ({list}) => {

  let {num} = useParams();

  let nav = useNavigate();
  return (
    <div className='main-container'>
      <div className='product-container detail-container'>
        <div className='datail-image'>
          <img src={list[num].src} alt="" />
        </div>
        <div className='detail-text'>
          <h4>{list[num].title}</h4>
          <p>
            <span>{list[num].price}</span>
            <span>{list[num].delivery ==="free"? "무료배송" : "배송비 :" + list[num].delivery+"원"}</span>
         </p>
         <Link to='/List'>목록으로 돌아가기</Link>
        </div>
      </div>
    </div>
  )
}

export default ProductDetail

useParams를 이용해 해당 파라미터 정보를 가져와서 num에 저장
해당하는 num의 상품이 출력!!

라우트 실습1

프로젝트 생성

npx create-react-app project06

npm install axios react-router-dom

BrowserRouter

Routes

Route

각각 임포트

컴포넌트 생성 및 라우팅 설정
-메인페이지 : Main.jsx => /
-리스트페이지 : List.jsx => / list
-상세페이지 : Detail.jsx => /detail

json 데이터 이동 방식

만약 리스트 오류가 가끔씩 나올 때

→ 조건을 걸어주자 list가 있을 때 list.map 돌려주기!!

메인화면

player List를 클릭하면 다음 페이지

해당 선수를 클릭하면

->해당 선수 상세 정보 페이지

Player.json (public)

{
    "list" : [
        {
            "name" : "조규성",
            "position" : "FW",
            "age" : 1998,
            "height" : 189,
            "weight" : 82,
            "team" : "FC 미트윌란",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207345228338.jpg"
        }, {
            "name" : "나상호",
            "position" : "MF",
            "age" : 1996,
            "height" : 173,
            "weight" : 70,
            "team" : "FC서울",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207313338443.jpg"
        } , {
            "name" : "손흥민",
            "position" : "MF",
            "age" : 1992,
            "height" : 183,
            "weight" : 78,
            "team" : "토트넘",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207324860557.jpg"
        } , {
            "name" : "황인범",
            "position" : "MF",
            "age" : 1996,
            "height" : 177,
            "weight" : 70,
            "team" : "올림피아코스",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207341162100.jpg"
        } , {
            "name" : "설영우",
            "position" : "DF",
            "age" : 1998,
            "height" : 180,
            "weight" : 72,
            "team" : "울산현대",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2023&name=%25EC%2582%25AC%25EC%25A7%2584_2023032713492058375.jpg"
        } , {
            "name" : "이기제",
            "position" : "DF",
            "age" : 1991,
            "height" : 176,
            "weight" : 68,
            "team" : "수원삼성",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2023&name=%25EC%2582%25AC%25EC%25A7%2584_202303211104076484.jpg"
        } , {
            "name" : "안현범",
            "position" : "MF",
            "age" : 1994,
            "height" : 178,
            "weight" : 72,
            "team" : "제주유나이티드",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2023&name=%25EC%2582%25AC%25EC%25A7%2584_2023061611424516588.jpg"
        } , {
            "name" : "이강인",
            "position" : "MF",
            "age" : 2001,
            "height" : 174,
            "weight" : 72,
            "team" : "파리 생제르맹 FC",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207332743807.jpg"
        } , {
            "name" : "이재성",
            "position" : "MF",
            "age" : 1992,
            "height" : 180,
            "weight" : 70,
            "team" : "FSV 마인츠05",
            "imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207333993248.jpg"
        }
    ]
}

Player.jsx

import React, { useState } from 'react'
import { Routes,Route } from 'react-router-dom';
import Main from './components/Main';
import List from './components/List';
import Detail from './components/Detail';
import './Player.css'

const Player = () => {
    // list state초기화
   const [list,setList] = useState([]);
  return (
    <div>
        <Routes>
            <Route path='/' element={<Main/>}></Route>
            <Route path='/list' element={<List list={list} setList={setList}/>}></Route>
            <Route path='/detail/:num' element={<Detail list={list}/>}></Route>
        </Routes>
    </div>
  )
}

export default Player

Main.jsx

import React from 'react'
import { Link } from 'react-router-dom'

const Main = () => {
  return (
    <div className='main-container'>
        <img src="https://www.playkfa.com/banner/1957a327-cf91-4a99-8f41-2c95c698dc45.png" 
        alt="" width='100%'/>
        <Link to='/list'>
        Player List
        </Link>
    </div>
  )
}

export default Main

List.jsx

import React, { useEffect } from 'react'
import Item from './Item'
import axios from 'axios'

const List = ({list,setList}) => {

    /*
    public 안의 json파일 데이터 가져오기
    */
  useEffect(()=>{
    axios
    .get('http://localhost:3000/player.json')
    .then((res)=>{
        setList(res.data.list)
    })
  },[])
  console.log(list);

  // 🎈🎈 React - Spring 연동
  useEffect(()=>{
    console.log("Spring으로 요청");
    // 경로
    let url = 'http://localhost:8090/SpringBoot2/PlayerList.do'
    // 서버 주소 변경(localhost 부분)
    axios
    // 어디로 보낼지! blob-> 멀티미디어를 다룰때!
    .post(url, {responseType : 'blob'})
    .then((res)=>{
      console.log(res.data);
      setList(res.data)
    })
  },[])

  return (
    <div className='list-container'>
        <h1>KOREA REPUBLIC</h1>
            <div className='list-item'>
                {list.map((item,index) => <Item item={item}
                key={index} index={index}></Item>)}
            </div>
        </div>
  )
}

export default List

Detail.jsx

import React from 'react'
import { useParams } from 'react-router-dom'

const Detail = ({list}) => {

    let {num} = useParams();
 
  return (
    <div  className='item-container'>
        <img src={list[num].imgSrc} alt=""  width='100%' />
       <table>
        <tbody>       
            <tr>
                <td>이름</td>
                <td>{list[num].name}</td>
            </tr>
            <tr>
                <td>포지션</td>
                <td>{list[num].position}</td>
            </tr>
            <tr>
                <td>나이</td>
                <td>{2023-list[num].age}</td>
            </tr>
            <tr>
                <td>,몸무게</td>
                <td>{list[num].height}cm,{list[num].weight}kg</td>
            </tr>
            <tr>
                <td></td>
                <td>{list[num].team}</td>
            </tr>
        </tbody>
       </table>
    </div>
  )
}

export default Detail

Item.jsx

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

const Item = ({item,index}) => {

    /*
    프로필 카드 클릭 시 해당 선수 상세 페이지로 이동
    /detail/index

    Item.jsx => 클릭 시 경로 이동 (/detail/idex)
    Detail.jsx => index 파라미터 설정
    Player.jsx => 라우트 경로 추가 (/detail/~)
    */
    const nav = useNavigate();

  return (
    <div className='item-container'
        onClick={()=>{
            nav(`/detail/${index}`)
        }}>

        <img src={item.imgSrc} alt="" />
        <table>
            <tbody>
                <tr>
                    <td>이름</td>
                    <td>{item.name}</td>
                </tr>
                <tr>
                    <td>포지션</td>
                    <td>{item.position}</td>
                </tr>
            </tbody>
        </table>
        
        </div>
  )
}

export default Item

다음 아래는 React - Spring 연동시 코드


→ 데이터를 보내줄 때
->어디로 보낼지! blob-> 멀티미디어를 다룰때!

profile
영이의 일상은 짱셔요

0개의 댓글