// Products.js
import { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
function Products() {
const [limit, setLimit] = useState(10);
const [offset, setOffset] = useState(0);
const location = useLocation();
const navigate = useNavigate();
const [products, setProducts] = useState([
{
id: 0,
title: "상품제목",
price: 1000,
},
]);
console.log("location", location);
console.log("pathname", location.pathname);
console.log("search", location.search);
//navigate query바뀐 것 인식해서 useEffect 실행되면 됨. (location.search 이용해서) 그러므로 의존성 배열에 location.search 넣어줌.
// 쿼리파라미터가 바뀌면 getFakeAPI도 다시 실행.
useEffect(() => {
const products = getFakeAPI(location.search);
setProducts(products);
}, [location.search]);
//버튼 눌러서 가져오기 함수
function onFetchClick() {
navigate(`?limit=${limit}&offset=${offset}`);
} //쿼리 파라미터를 다는게 네비게이트를 통해서 이루어지는게 중요!
return (
<>
{/* 필터 옵션도 있을 것 - limit과 offiset 바꿀 수 있도록 */}
<div>
limit:{" "}
<input value={limit} onChange={(e) => setLimit(e.target.value)} />
</div>
<div>
offset:{" "}
<input value={offset} onChange={(e) => setOffset(e.target.value)} />
</div>
<button onClick={onFetchClick}> 가져오기 </button>
{products.map((product) => (
<div key={product.id}>
{product.id} {product.title} {product.price}
</div>
))}
</>
);
}
export default Products;
// 백엔드 흉내내는 코드
function getFakeAPI(search) {
const urlSerachParams = new URLSearchParams(search);
const offset = urlSerachParams.get("offset");
const limit = urlSerachParams.get("limit");
// 백엔드에서는 req.query.offset, req.query.limit
let index = offset;
const fakeProducts = [];
for (let i = 0; i < limit; i += 1) {
const fakeProduct = {
id: index,
title: `상품제목${index}`,
price: 1000 * Number(index),
};
index++;
fakeProducts.push(fakeProduct);
}
return fakeProducts;
}
이전 기본 단계에서 바뀐 것 _UPDATE
- input창 만들어서 limit, offset 검색하는 창 만들어줌.
- useNavigate hook을 넣어서 데이터 가져오는 버튼 만들어줌.
- useNavigate안에 query가 바뀐 것을 인식해서 location.search를 이용해 useEffect를 실행하게 함.
쿼리파라미터가 바뀌면 getFakeAPI도 다시 실행되어 인풋창에 넣은
limit, offset 값에 따라 setProducts도 바뀜.
<검색 전>
<검색 후> 가져오기 버튼 누르면 위에 검색한 limit, offset값에 따라
위에 쿼리파라미터가 바뀌고 상품조회됨.
조회된 상품 목록 클릭하면 제품 상세페이지로 넘어가기
- Link 이용하여 경로 설정해주기
- 상세페이지(.js) route 설정해주기 (링크경로만 만들어주면 안됨. App.js에 route지정이 안되어있기 때문)
// App.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Users from "./Users";
import Products from "./Products";
import ProductDetail from "./ProductDetail";
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route path="users/:id" element={<Users />} />
{/* //useParams hook통해서 id 값 가져옴 //특정 정보 가져올 때 */}
<Route path="products" element={<Products />} />
{/* //쿼리 파라미터 - 성질에 따라 바뀌게 될 때 / 쿼리파라미터는 패스파라미터랑 다르게 id 같이 등록할 필요 없음. search를 이용해 가져옴.*/}
<Route path="product/:id" element={<ProductDetail />} /> // id값을 넣은 상세페이지 route
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
//Product.js
<button onClick={onFetchClick}> 가져오기 </button>
{products.map((product) => (
<Link key={product.id} to={`/product/${product.id}`}>
{/* key도 위로 옮겨줌 Link가 최상단에 있으니까 */}
{/* 그리고 이렇게 링크 경로를 만들어 주기만 하면 안되고 App.js에 route 지정이 안되어있어서 등록해줘야함. */}
<div>
{product.id} {product.title} {product.price}
</div>
</Link>
))}
기존에 있던 map의 key값도 최상단인 Link태그에 올려줌.
경로를 /product/아이디로 지정함.
```
```
//ProductDetail.js
import { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
//배열 모양 까먹지 않기 기록해놓은 것.
// charges:[
// {
// id: 1,
// name: "배송비",
// price: 2500
// }
// ],
// review: [
// {
// id: 0,
// comment:" 너무 좋아요",
// star: 4.5
// }
// ]
function ProductDetail() {
const [product, setProduct] = useState({
id: 0,
tite: "상품0",
price: 0,
charges: [],
review: [],
}); //여기서 기본값을 지정하지 않으면 밑에 product.id ~ 여기에
undefined이 뜸. 그래서 초기값 설정해 준 것임.
const params = useParams();
const productId = params.id;
//제품 상세 정보 가져오기
useEffect(() => {
//api호출
const product = getFakeAPI(productId);
setProduct(fakeProduct);
}, [productId]);
return (
<>
{product.id} {product.title} {product.price}
</>
);
}
export default ProductDetail;
<검색 전>
<검색 후>
<상세페이지 클릭하여 들어 간 후> ( 제품 정보 미등록으로 초기값으로 나옴)