index.js
import React from "react";
import ReactDOM from "react-dom/client";
import AppProducts from "./AppProducts";
import "./index.css";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<AppProducts />
</React.StrictMode>
);
AppProduct.jsx
import React from "react";
import { useState } from "react";
import Product from "./components/Product";
export default function AppProducts() {
const [showProducts, setShowProducts] = useState(true);
return (
<div>
{showProducts && <Product />}
<button
onClick={() => {
setShowProducts((show) => !show);
}}
>
Toggle
</button>
</div>
);
}
Product.jsx
import React from "react";
import { useEffect } from "react";
import { useState } from "react";
export default function Product() {
const [products, setProducts] = useState([]);
const [checked, setChecked] = useState(false);
const handleChange = () => {
setChecked((prev) => !prev);
};
// 컴포넌트 안에 state가 변경되면 그 컴포넌트를 다시 호출하는데
// fetch로 데이터를 불러와서 setProducts로 products의 상태를 업데이트 해주는 것까지는 좋지만
// 상태가 바뀌었으니 Product 컴포넌트가 또 호출되고 데이터를 fetch해오고 setProducts로 상태를 업데이트하고 상태가 바뀌었으니 또 Product를 호출하면서 무한루프가 발생한다
// 이때 useEffect() 훅을 사용한다
// fetch("data/products.json")
// .then((res) => res.json())
// .then((data) => {
// console.log(data);
// setProducts(data);
// })
// .catch((e) => {
// console.log(e);
// });
useEffect(() => {
fetch(`data/${checked ? "sale_" : ""}products.json`)
.then((res) => res.json())
.then((data) => {
console.log(data);
setProducts(data);
})
.catch((e) => {
console.log(e);
});
// 콜백에서 실행할 로직을 다 끝내고 실행할 함수 등록
// 다음 useEffect를 실행하기 직전, 혹은 언마운트 시에 실행된다
return () => {
console.log("clear!");
};
// 2번째 인자로 넘겨주는 배열의 값들 중 하나라도 state가 바뀌면 useEffect에 콜백으로 등록된 함수를 실행한다
// 빈 배열을 넣어주면 state변화를 감지하지 않겠다는 뜻이므로 Product 컴포넌트가 호출될 때 한번만 실행된다
}, [checked]);
return (
<div>
<input id="checkbox" type="checkbox" onChange={handleChange} />
<label htmlFor="checkbox">SALE</label>
<ul>
{/* 배열을 map으로 돌려서 리턴해줄때 li 요소 안에 key 속성을 무조건 넣어줘야 한다 */}
{/* 보통 배열안에 담긴 id 값을 넣곤 하는데 없을 경우 map 자체에서 2번째 인자로 넘겨주는 인덱스 값을 넣어주면 된다 */}
{/* key값은 그 배열 안에서만 고유하면 되고 그 밖으로는 같은 값이 중복되어도 상관없다 */}
{products.map((product, index) => {
return (
<li key={index}>
<article>
<h3>{product.name}</h3>
<p>{product.price}</p>
</article>
</li>
);
})}
</ul>
</div>
);
}
products.json, sale_products.json
[
{
"name": "jeans",
"price": "20"
},
{
"name": "y-shirt",
"price": "30"
},
{
"name": "pants",
"price": "70"
}
]
[
{
"name": "snacks",
"price": "5"
},
{
"name": "socks",
"price": "3"
}
]
View