[๐ŸŽ์ฝ”๋”ฉ์• ํ”Œ ๊ฐ•์˜์š”์•ฝ]URL ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ƒ์„ธํŽ˜์ด์ง€ 100๊ฐœ ๋งŒ๋“ค๊ธฐ ๐ŸŽฏ

๐ŸŒˆ KJยท2025๋…„ 6์›” 3์ผ

codingapple

๋ชฉ๋ก ๋ณด๊ธฐ
20/23
post-thumbnail

์ƒ์„ธํŽ˜์ด์ง€์— ์‹ค์ œ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ ๋„ฃ๊ธฐ ๐Ÿ“‹

์ž„์‹œ ํ…์ŠคํŠธ๋งŒ ์žˆ์œผ๋ฉด ๋ฐ‹๋ฐ‹ํ•˜๋‹ˆ๊นŒ ์‹ค์ œ ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๋„ฃ์–ด๋ด…์‹œ๋‹ค!

props๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๊ธฐ

App.js:

<Route path="/detail" element={ <Detail shoes={shoes}/> }/>

Detail.js:

<div className="container">
  <div className="row">
    <div className="col-md-6">
      <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
    </div>
    <div className="col-md-6 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">์ฃผ๋ฌธํ•˜๊ธฐ</button>
    </div>
  </div> 
</div>

props ์‚ฌ์šฉ ์ด์œ :

  • Detail.js์—์„œ shoes state๋ฅผ ๋˜ ๋งŒ๋“ค๋ฉด ๋‚˜์ค‘์— ๋‘ ๊ตฐ๋ฐ ์ˆ˜์ •ํ•ด์•ผ ํ•ด์„œ ๋น„ํšจ์œจ์ 
  • ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ์œ ์ง€๋ฅผ ์œ„ํ•ด props ์‚ฌ์šฉ ๊ถŒ์žฅ โš ๏ธ

์ƒ์„ธํŽ˜์ด์ง€ ์—ฌ๋Ÿฌ ๊ฐœ ๋งŒ๋“ค๊ธฐ ๐Ÿ”ข

๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•

<Route path="/detail/0" element={ <Detail shoes={shoes}/> }/>
<Route path="/detail/1" element={ <Detail shoes={shoes}/> }/>
<Route path="/detail/2" element={ <Detail shoes={shoes}/> }/>

๋ฌธ์ œ์ : ์ƒํ’ˆ์ด 100๋งŒ ๊ฐœ๋ผ๋ฉด Route๋„ 100๋งŒ ๊ฐœ ๋งŒ๋“ค์–ด์•ผ ํ•จ ๐Ÿ˜ฑ

URL ํŒŒ๋ผ๋ฏธํ„ฐ ์‚ฌ์šฉํ•˜๊ธฐ (๊ถŒ์žฅ)

<Route path="/detail/:id" element={ <Detail shoes={shoes}/> }/>

URL ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฌธ๋ฒ•

  • /:id - "์•„๋ฌด ๋ฌธ์ž"๋ฅผ ์˜๋ฏธ
  • /detail/์•„๋ฌด๊ฑฐ๋‚˜ ์ž…๋ ฅ ์‹œ <Detail> ์ปดํฌ๋„ŒํŠธ ํ‘œ์‹œ
  • ์Šฌ๋ž˜์‹œ(/)๋Š” ๋‹จ์–ด ๊ฐ„ ๋„์–ด์“ฐ๊ธฐ์šฉ์œผ๋กœ ์‚ฌ์šฉ

์ด์ œ ๋‹ค์Œ URL๋“ค์ด ๋ชจ๋‘ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

  • /detail/0
  • /detail/1
  • /detail/2

useParams๋กœ URL ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๐ŸŽฃ

ํŽ˜์ด์ง€๋งˆ๋‹ค ๋‹ค๋ฅธ ์ƒํ’ˆ์„ ๋ณด์—ฌ์ฃผ๋ ค๋ฉด ํ˜„์žฌ URL์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

function Detail(props){
  let {id} = useParams();
  console.log(id)  // URL์˜ :id ๋ถ€๋ถ„ ๊ฐ’ ์ถœ๋ ฅ
  
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
        </div>
        <div className="col-md-6 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">์ฃผ๋ฌธํ•˜๊ธฐ</button>
        </div>
      </div>
    </div>
  )
}

useParams ์ž‘๋™ ์›๋ฆฌ

  • /detail/1 ์ ‘์† โ†’ id ๋ณ€์ˆ˜์— "1" ์ €์žฅ
  • /detail/2 ์ ‘์† โ†’ id ๋ณ€์ˆ˜์— "2" ์ €์žฅ
  • props.shoes[id].title๋กœ ํ•ด๋‹น ์ƒํ’ˆ๋ช… ํ‘œ์‹œ

๋‹ค์ค‘ URL ํŒŒ๋ผ๋ฏธํ„ฐ

// path ์„ค์ •
<Route path="/detail/:category/:id" element={<Detail />} />

// useParams ์‚ฌ์šฉ
let {category, id} = useParams();
// /detail/shoes/1 โ†’ category="shoes", id="1"

์‘์šฉ ๋ฌธ์ œ: ๋ฐ์ดํ„ฐ ์ •๋ ฌ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ ๐Ÿค”

๋ฌธ์ œ ์ƒํ™ฉ

์ƒํ’ˆ์„ ๊ฐ€๋‚˜๋‹ค์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์—ˆ๋‹ค๊ณ  ๊ฐ€์ •:

  1. ์ •๋ ฌ ์ „: White and Black์ด 0๋ฒˆ ์ƒํ’ˆ
  2. ์ •๋ ฌ ํ›„: Grey Yordan์ด 0๋ฒˆ ์ƒํ’ˆ์ด ๋จ
  3. ๊ฒฐ๊ณผ: /detail/0 ์ ‘์† ์‹œ ๋‹ค๋ฅธ ์ƒํ’ˆ์ด ๋ณด์ž„!

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ํžŒํŠธ ๐Ÿ’ก

๋ฐฐ์—ด ์ธ๋ฑ์Šค ๋Œ€์‹  ๊ณ ์œ ํ•œ ์‹๋ณ„์ž(id)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!


๋ณด์ถฉ ์„ค๋ช… ๐Ÿ’ก

URL ํŒŒ๋ผ๋ฏธํ„ฐ vs ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง ๐Ÿ”

URL ํŒŒ๋ผ๋ฏธํ„ฐ (Path Parameter):

/detail/123          โ† 123์€ URL ํŒŒ๋ผ๋ฏธํ„ฐ
/user/john/posts/5   โ† john๊ณผ 5๋Š” URL ํŒŒ๋ผ๋ฏธํ„ฐ

์ฟผ๋ฆฌ ์ŠคํŠธ๋ง (Query String):

/products?category=shoes&size=large
/search?q=react&page=2

useParams vs useSearchParams ๋น„๊ต

1. useParams - URL ํŒŒ๋ผ๋ฏธํ„ฐ์šฉ

// URL: /product/123
const { id } = useParams();
console.log(id); // "123"

2. useSearchParams - ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์šฉ

// URL: /products?category=shoes&page=2
const [searchParams] = useSearchParams();
console.log(searchParams.get('category')); // "shoes"
console.log(searchParams.get('page')); // "2"

์•ˆ์ „ํ•œ ์ƒ์„ธํŽ˜์ด์ง€ ๊ตฌํ˜„ ๐Ÿ›ก๏ธ

1. ID ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ๋ฐฉ์‹

function Detail(props) {
  const { id } = useParams();
  
  // ์ธ๋ฑ์Šค ๋Œ€์‹  ID๋กœ ์ฐพ๊ธฐ
  const product = props.shoes.find(shoe => shoe.id === parseInt(id));
  
  if (!product) {
    return <div>์ƒํ’ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.</div>;
  }
  
  return (
    <div>
      <h4>{product.title}</h4>
      <p>{product.content}</p>
      <p>{product.price}์›</p>
    </div>
  );
}

2. ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™”

function Detail(props) {
  const { id } = useParams();
  const navigate = useNavigate();
  
  useEffect(() => {
    // ์œ ํšจํ•˜์ง€ ์•Š์€ ID๋ฉด 404๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
    const product = props.shoes.find(shoe => shoe.id === parseInt(id));
    if (!product) {
      navigate('/404', { replace: true });
    }
  }, [id, props.shoes, navigate]);
  
  // ... ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง
}

๋™์  ๋ผ์šฐํŒ… ๊ณ ๊ธ‰ ํŒจํ„ด ๐ŸŽฏ

1. ์˜ต์…”๋„ ํŒŒ๋ผ๋ฏธํ„ฐ

// ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์—†์„ ์ˆ˜๋„
<Route path="/products/:category?" element={<Products />} />

function Products() {
  const { category } = useParams();
  
  // category๊ฐ€ undefined์ผ ์ˆ˜ ์žˆ์Œ
  return category ? (
    <div>{category} ์นดํ…Œ๊ณ ๋ฆฌ ์ƒํ’ˆ๋“ค</div>
  ) : (
    <div>์ „์ฒด ์ƒํ’ˆ</div>
  );
}

2. ์™€์ผ๋“œ์นด๋“œ์™€ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํ•ฉ

<Route path="/files/*" element={<FileViewer />} />

function FileViewer() {
  const location = useLocation();
  const filePath = location.pathname.replace('/files/', '');
  
  // /files/docs/readme.txt โ†’ filePath = "docs/readme.txt"
}

์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ โšก

1. ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ํ™œ์šฉ

function Detail(props) {
  const { id } = useParams();
  
  const product = useMemo(() => {
    return props.shoes.find(shoe => shoe.id === parseInt(id));
  }, [props.shoes, id]);
  
  return product ? <ProductView product={product} /> : <NotFound />;
}

2. ๋ฐ์ดํ„ฐ ์‚ฌ์ „ ๋กœ๋”ฉ

// ์ƒํ’ˆ ๋ชฉ๋ก์—์„œ ์ƒ์„ธํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๋งํฌ
function ProductCard({ product }) {
  const handleMouseEnter = () => {
    // ๋งˆ์šฐ์Šค ํ˜ธ๋ฒ„ ์‹œ ์ƒ์„ธ ๋ฐ์ดํ„ฐ ๋ฏธ๋ฆฌ ๋กœ๋“œ
    preloadProductDetails(product.id);
  };
  
  return (
    <Link 
      to={`/detail/${product.id}`}
      onMouseEnter={handleMouseEnter}
    >
      {product.title}
    </Link>
  );
}

URL ์„ค๊ณ„ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค ๐Ÿ“

1. ์ง๊ด€์ ์ธ URL ๊ตฌ์กฐ

โœ… ์ข‹์€ ์˜ˆ:
/products/123
/categories/electronics/products/456
/users/john/orders/789

โŒ ๋‚˜์œ ์˜ˆ:
/page?type=product&id=123
/electronics123
/johnorders789

2. RESTful URL ํŒจํ„ด

// ์ƒํ’ˆ ๊ด€๋ จ
/products           // ์ƒํ’ˆ ๋ชฉ๋ก
/products/123       // ์ƒํ’ˆ ์ƒ์„ธ
/products/new       // ์ƒํ’ˆ ์ถ”๊ฐ€
/products/123/edit  // ์ƒํ’ˆ ์ˆ˜์ •

// ์‚ฌ์šฉ์ž ๊ด€๋ จ  
/users/456          // ์‚ฌ์šฉ์ž ํ”„๋กœํ•„
/users/456/orders   // ์‚ฌ์šฉ์ž ์ฃผ๋ฌธ ๋ชฉ๋ก
/users/456/orders/789  // ํŠน์ • ์ฃผ๋ฌธ ์ƒ์„ธ

0๊ฐœ์˜ ๋Œ“๊ธ€