이번 kidsney 프로젝트를 하며 가장 많이 친해진 useEffect ^^
생각보다 내가 useEffect에 대해 잘 모르고 있었구나 싶었을 정도로,, 날 좀 힘들게 했던 녀석(?)
키즈니 프로젝트 중 가장 힘들었던 부분이 좋아요를 클릭하고 그 상태를 유지하는 것이다. (새로고침을 하더라도)
데이터 통신에는 전혀 문제가 없고, useEffect를 활용하여 컴포넌트가 mount되는 시점에 하트가 저장되어있는 상태를 저장해서 하트부분에 조건부 렌더링을 해주었는데 이게 전혀 먹히지 않았다.
알고 보니 하트가 클릭된 상태를 useEffect에 저장을 하더라도, useEffect는 비동기적으로 업무를 처리하기 때문에 렌더링이 다 된 이후 fetch를 한다.
이 문제를 해결한 나의 방식을 말해보겠다-!
핵심은 &&연산자이다!
참고) 상품의 리스트를 담은 <productList/>
그리고 리스트 안에 담겨있는 상품 하나하나가 <product />
이다.
<productList/>
내에서 위시리스트 상품 목록 전체를 fetch를 이용하여 전송받는다. // productList
const getWishList = () => {
fetch(`http:/${API}/users/wishlist`, {
headers: {
Authorization:
'localStorage.getItem(Token)',
},
})
.then(res => {
if (!res.ok) {
console.log('error');
}
return res.json();
})
.then(data => {
setWishListId(data.wish_list.map(list => list.id));
})
.catch(error => console.error(error.message));
};
<product />
가 포함을 하고 있는지의 여부를 나타낸 값을(불리언 값)을 isHeart라는 변수에 담아서 prop으로 보낸다.isHeart={wishListIds.includes(product.id)}
return (
<div className="productList">
{wishListIds.length > 0 &&
products.map(product => (
<Product
wishListIds={wishListIdx}
isHeart={wishListIdx.includes(product.id)}
key={product.id}
product={product}
/>
))}
여기서 주목해야할 부분이 wishListIds.length > 0 &&
이다.
저기 있는 &&연산자를 적어주지 않으면 isHeart라는 값이 undefined로 product에 전송이 된다.
useEffect가 비동기적으로 업무를 처리하기 때문에 wishListIds의 값이 다 받아지기도 전에 렌더링을 해버려서 값이 저장되지 않은 상태로 props에 내려주게 된다.
그렇기 때문에 &&연산자를 꼭! 써서 wishListIds값이 받아진 후에야 props를 전달할 수 있도록 만들어주는 것!!
<product />
에서 isHeart를 받은 뒤, 하트가 클릭되었는지를 결정해주는 isAdded state의 초기값으로 해당 props를 적어준다. const Product = ({ product, direction, isHeart, wishListIds }) => {
const { id, name, price, image_urls } = product;
const [isAdded, setIsAdded] = useState(isHeart);
const addToWishList = () => {
fetch(`${API}/users/wishlist?product-id=${id}`, {
method: 'POST',
headers: {
Authorization: localStorage.getItem(Token),
},
body: JSON.stringify({ id: id }),
})
.then(res => {
if (!res.ok) {
console.log('error');
}
return res.json();
})
.then(data => {
console.log(data);
setIsAdded(data.message === 'ADDED');
})
.catch(error => console.error(error.message));
};
<button className="heartBtn" onClick={addToWishList}>
<i className={isAdded ? 'fas fa-heart' : 'far fa-heart'} />
</button>
핵심은,
새로고침을 해도 하트 상태를 유지시키고 싶다면 &&연산자를 이용하여 해당 하트 클릭 상태가 저장된다면 prop 으로 자식 컴포넌트에 하트 클릭된 상태(불리언 값)을 보내주고, 받아낸 하트 클릭 상태를 state의 초기값으로 설정을 해주어야 유지가 된다.
비동기처리과정에 대해 확실히 알았다. && 연산자 잘 활용해보자-!!!!