๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
[๊ฐœ๋ฐœ] Practice/React

[React] React Router 3 : URL ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ƒ์„ธ ํŽ˜์ด์ง€ 100๊ฐœ ๋งŒ๋“ค๊ธฐ

by Connecting-the-dots 2022. 3. 24.
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ’ก ์‹ค์Šต ํฌ์ธํŠธ!

  • ์˜ค๋Š˜์€ URL ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ์ด ๋œ ์ƒ์„ธ ํŽ˜์ด์ง€๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค.

๐Ÿ’œ Detail Component ์— ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ

// ์ „์ฒด ์ฝ”๋“œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
// ์ „์ฒด ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์„œ ๋ถˆํ•„์š”ํ•œ ๋ถ€๋ถ„์€ ์ œ์™ธํ–ˆ๋‹ค.

import Main from './Main'
import Detail from './Detail';

function App() {

  let [shoes, setShoes] = useState(Data);
  
  return (
    <div className="App">

          {/* Main */}
          <Route exact path='/'>
            <Main shoes={shoes}/>
          </Route>
          
          {/* Detail */}
          <Route path='/detail'>
            <Detail shoes={shoes}/> // ์ˆ˜์ •
          </Route>
    
    </div>
  );
}
  • Detail Component ์— ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ์„ ํ•ด์ฃผ๋ ค๋ฉด ๋ถ€๋ชจ Component ์ธ App Component ์—์„œ Detail Component ๋กœ  shoes ๋ผ๋Š” state ๋ฅผ ์ „์†ก๋ฐ›์•„์™€์•ผ ํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ, shoes ๋ผ๋Š” ๋ณ€์ˆ˜๋กœ shoes ๋ผ๋Š” state ๋ฅผ Detail Component ์— props ๋กœ ์ „์†กํ•ด์ฃผ์—ˆ๋‹ค.
import React, { useState } from "react";
import { useHistory } from 'react-router-dom';

function Detail(props) {

    let history = useHistory();

    return (
        <div className="container">
              <div className="row">
                <div className="col-md-7">
                  <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
                </div>
                <div className="col-md-5 mt-4">
                  <h4 className="pt-5">{props.shoes[0].title}</h4>
                  <p>{props.shoes[0].content}</p>
                  <p>{props.shoes[0].price}</p>
                  <button className="btn btn-danger mx-1">์ฃผ๋ฌธํ•˜๊ธฐ</button> 
                  <button className="btn btn-danger mx-1" onClick={()=>{history.goBack()}}>๋’ค๋กœ๊ฐ€๊ธฐ</button> 
                </div>
              </div>
        </div>  
    )
}

export default Detail;
  • ์œ„์™€ ๊ฐ™์ด Detail Component ์—์„œ๋Š” props ๋ฅผ ๊ฐ€์ง€๊ณ , shoes ๋ผ๋Š” ๋ณ€์ˆ˜์— ๋‹ด๊ธด shoes ๋ผ๋Š” state ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • shoes ๊ฐ€ ๋‹ด๊ธด useState() ํ•จ์ˆ˜๋ฅผ Detail Component ๊ฐ€ ์•„๋‹ˆ๋ผ App Component ์— ๋งŒ๋“  ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๋Š” ํ•ญ์ƒ ์œ„์—์„œ ์•„๋ž˜๋กœ ํ˜๋Ÿฌ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ํ•˜์— ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ 2๊ฐœ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •์„ ํ•ด๋ณด์ž.
    • ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ2 ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ1 ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธฐ๋ฉด, ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ2 ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•ด์„œ ๋‹ค์‹œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ1 ๋กœ ์ „์†กํ•ด์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์ƒ๊ธด๋‹ค.
    • ๋”ฐ๋ผ์„œ, ์ค‘์š” ๋ฐ์ดํ„ฐ๋Š” ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” props ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ’œ ์ƒ์„ธ ํŽ˜์ด์ง€ 3๊ฐœ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

  • ์ƒ์„ธ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” URL ์ฃผ์†Œ๋ฅผ ์–ด๋–ค ์‹์œผ๋กœ ๋งŒ๋“ค์ง€๋ถ€ํ„ฐ ์ƒ๊ฐํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.
  • ๋‚˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ธ”๋กœ๊ทธ, ์‡ผํ•‘๋ชฐ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค. 
    • /detail/0 ์œผ๋กœ ์ ‘์†ํ•˜๋ฉด 0๋ฒˆ์งธ ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€ ๋ณด์—ฌ์ฃผ๊ธฐ
    • /detail/1 ์œผ๋กœ ์ ‘์†ํ•˜๋ฉด 1๋ฒˆ์งธ ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€ ๋ณด์—ฌ์ฃผ๊ธฐ
    • /detail/2 ์œผ๋กœ ์ ‘์†ํ•˜๋ฉด 2๋ฒˆ์งธ ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€ ๋ณด์—ฌ์ฃผ๊ธฐ
function App(){
  return (
    <div>
    
        <Route path="/detail/0">
          <Detail shoes={shoes}/>
        </Route>
        
        <Route path="/detail/1">
          <Detail shoes={shoes}/>
        </Route>
        
        <Route path="/detail/2">
          <Detail shoes={shoes}/>
        </Route>
        
    </div>
  )
}
  • ํ•˜์ง€๋งŒ ์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋น„ํšจ์œจ์ ์ด๋ฉฐ ํ™•์žฅ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
  • ๋”ฐ๋ผ์„œ, URL ์„ ๋งŒ๋“ค ๋•Œ์—๋Š” URL ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฌธ๋ฒ•์„ ์ด์šฉํ•ด ์ถ•์•ฝ์„ ์‹œ์ผœ์ฃผ๋Š” ๊ฒŒ ์ข‹๋‹ค.
function App(){
  return (
    <div>
    
      <Route path='/detail/:id'>
        <Detail shoes={shoes} />
      </Route>
        
    </div>
  )
}
  • ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ๊น”๋”ํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ถ•์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฌธ๋ฒ•์€ ์ฝœ๋ก  ๊ธฐํ˜ธ( : )์™€ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • ๋‚˜์˜ ๊ฒฝ์šฐ :id ๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, ์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ /detail/ ๋’ค์— ์–ด๋–ค ๋ฌธ์ž๊ฐ€ ์ž…๋ ฅ๋˜์–ด๋„ Detail Component ๋ฅผ ๋ณด์—ฌ๋‹ฌ๋ผ๋Š” ์˜๋ฏธ๊ฐ€ ๋œ๋‹ค.
  • ํ•˜์ง€๋งŒ ๊ถ๊ทน์ ์œผ๋กœ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ /detail/ ๋’ค์— ๋ถ™๋Š” 0, 1, 2 ๋ผ๋Š” ์ˆซ์ž์— ๋”ฐ๋ผ ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
import React, { useState } from "react";
import { useHistory, useParams } from 'react-router-dom';

function Detail(props) {

    let history = useHistory();
    let { id } = useParams();

    return (
        <div className="container">
              <div className="row">
                <div className="col-md-7">
                  <img src={`https://codingapple1.github.io/shop/shoes${props.shoes[id].id + 1}.jpg`} width="100%" />
                </div>
                <div className="col-md-5 mt-4">
                  <h4 className="pt-5">{props.shoes[id].title}</h4>
                  <p>{props.shoes[id].content}</p>
                  <p>{props.shoes[id].price}</p>
                  <button className="btn btn-danger mx-1">์ฃผ๋ฌธํ•˜๊ธฐ</button> 
                  <button className="btn btn-danger mx-1" onClick={()=>{history.goBack()}}>๋’ค๋กœ๊ฐ€๊ธฐ</button> 
                </div>
              </div>
        </div>  
    )
}

export default Detail;
  • ์ฆ‰, URL ์ƒ์—์„œ :id ์ž๋ฆฌ์— ์ž…๋ ฅํ•œ ์ˆซ์ž๋ฅผ ์ธ๋ฑ์Šค๊ฐ€ ๋“ค์–ด์žˆ๋˜ ์ž๋ฆฌ์— ๋“ค์–ด๊ฐ€๊ธธ ์›ํ•œ๋‹ค.
  • ์ด๋ฅผ ์œ„ํ•ด Router ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์‚ฌ์šฉ๋ฒ•์„ ์ฐพ์•„๋ณด๋ฉด useParams() ๋ผ๋Š” hook ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.
    (React Router Library - useParams() ๋ณด๋Ÿฌ๊ฐ€๋ ค๋ฉด ํด๋ฆญ!!)
  • useParams() ์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
    • useParams ๋ฅผ import ํ•ด์ค€๋‹ค.
    • import ํ•œ useParams ๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅํ•œ๋‹ค.
let { id } = useParams();
  • useParams() ํ•จ์ˆ˜์—๋Š” URL ์— ์ ํžŒ ๋ชจ๋“  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ {ํŒŒ๋ผ๋ฏธํ„ฐ1, ํŒŒ๋ผ๋ฏธํ„ฐ2} ์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ €์žฅํ•ด์ค€๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น ๋ฌธ๋ฒ•์„ ์ด์šฉํ•˜๋ฉด ๋”ฐ๋กœ๋”ฐ๋กœ ๋ณ€์ˆ˜๋กœ ๋นผ์„œ ์ €์žฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๋‚ด๊ฐ€ URL ์— /detail/0 ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค๋ฉด useParams() ํ•จ์ˆ˜๋Š” { 0 } ์œผ๋กœ ์ €์žฅ๋˜์–ด ์žˆ์„ ๊ฑฐ๊ณ , ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น ๋ฌธ๋ฒ•์„ ํ†ตํ•ด id ์— 0 ์ด๋ผ๋Š” ๊ฐ’์ด ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๐Ÿ’œ ์›์ž๋ฃŒ์˜ ๋ณ€๊ฒฝ์— ์˜ํ–ฅ๋ฐ›์ง€ ์•Š๋Š” ์ƒ์„ธ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ

import React, { useState } from "react";
import { useHistory, useParams } from 'react-router-dom';

function Detail(props) {

    let history = useHistory();
    let { id } = useParams();
    
    let findId = props.shoes.find(function(item) {
        return item.id == id;
    });

    return (
        <div className="container">
        <div className="row">
          <div className="col-md-7">
            <img src={`https://codingapple1.github.io/shop/shoes${parseInt(findId.id)+1}.jpg`} width="100%" />
          </div>
          <div className="col-md-5 mt-4">
            <h4 className="pt-5">{findId.title}</h4>
            <p>{findId.content}</p>
            <p>{findId.price}</p>
            <button className="btn btn-danger mx-1">์ฃผ๋ฌธํ•˜๊ธฐ</button> 
            <button className="btn btn-danger mx-1" onClick={()=>{history.goBack()}}>๋’ค๋กœ๊ฐ€๊ธฐ</button> 
          </div>
        </div>
      </div>
    )
}

export default Detail;
  • ๊ธฐ์กด์—๋Š” shoes ๋ผ๋Š” state ์•ˆ์— ์ €์žฅ๋œ ์ž๋ฃŒ๋“ค์˜ ์ธ๋ฑ์Šค์™€ id ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ผ์น˜์‹œ์ผฐ๊ธฐ ๋•Œ๋ฌธ์—, shoes ๋ผ๋Š” state ์•ˆ์— ์ €์žฅ๋œ ์ž๋ฃŒ๋“ค์˜ ์ˆœ์„œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด ์ธ๋ฑ์Šค๊ฐ€ ๋ฐ”๋€Œ์–ด๋ฒ„๋ฆฌ๋ฉด id ํŒŒ๋ผ๋ฏธํ„ฐ๋„ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค.
  • ๋”ฐ๋ผ์„œ ์ด๋Ÿฐ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ์ƒ์„ธ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด JavaScript ๋ฌธ๋ฒ•์„ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • find() ๋ผ๋Š” ES6 ์‹ ๋ฌธ๋ฒ•์„ ์ด์šฉํ•˜๋ฉด array ์•ˆ์—์„œ ์›ํ•˜๋Š” ์ž๋ฃŒ๋ฅผ ์ฐพ๊ธฐ ์‰ฝ๋‹ค.
let findId = props.shoes.find(function(item) {
    return item.id == id;
});
  • props.shoes ๋Š” array ์ž๋ฃŒํ˜•์ด๋ฏ€๋กœ ์ด ๋’ค์— find() ํ•จ์ˆ˜ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  find() ํ•จ์ˆ˜ ์•ˆ์—๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ์กฐ๊ฑด์„ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
  • ์ž„์˜๋กœ ์ž‘์„ฑํ•œ item ์ด๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” props.shoes ์— ์ €์žฅ๋œ array ์ž๋ฃŒํ˜•์˜ ์ž๋ฃŒ ํ•˜๋‚˜ํ•˜๋‚˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • return ์กฐ๊ฑด์‹ ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ํ•ด๋‹น ์กฐ๊ฑด์‹์— ๋Œ€ํ•ด ์ฐธ์ธ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š”๋ฐ, ์ด๋ฅผ ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜์— ์ €์žฅํ•˜์—ฌ ํ•„์š”ํ•œ ๊ณณ์— ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • ์ฐธ๊ณ ๋กœ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์กฐ๊ฑด์‹์€ props.shoes ์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์ž๋ฃŒ ํ•˜๋‚˜ํ•˜๋‚˜์˜ id ์™€ URL ์—์„œ ๋ฐ›์•„์˜จ id ๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๊ฐ™์€ ๊ฒƒ๋งŒ ์ฐพ์•„๋‹ฌ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.
  • ์ฐพ์€ ๋ฐ์ดํ„ฐ๋Š” object ํƒ€์ž…์œผ๋กœ findId ๋ณ€์ˆ˜์— ์ €์žฅ๋˜๋ฏ€๋กœ ํ•ด๋‹น ๋ฐ์ดํ„ฐ์˜ id, title, content, price ์™€ ๊ฐ™์€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ค๋ ค๋ฉด findId.id, findId.title, findId.content, findId.price ์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๊ฐ€์ง€๊ณ  ์˜ค๋ฉด ๋œ๋‹ค.

 

728x90
๋ฐ˜์‘ํ˜•