[React] useEffect 렌더링이 안될 땐 &&연산자를 활용하자-!

Hyodduru ·2022년 4월 10일
3

React

목록 보기
10/22

이번 kidsney 프로젝트를 하며 가장 많이 친해진 useEffect ^^

생각보다 내가 useEffect에 대해 잘 모르고 있었구나 싶었을 정도로,, 날 좀 힘들게 했던 녀석(?)

키즈니 프로젝트 중 가장 힘들었던 부분이 좋아요를 클릭하고 그 상태를 유지하는 것이다. (새로고침을 하더라도)

데이터 통신에는 전혀 문제가 없고, useEffect를 활용하여 컴포넌트가 mount되는 시점에 하트가 저장되어있는 상태를 저장해서 하트부분에 조건부 렌더링을 해주었는데 이게 전혀 먹히지 않았다.

알고 보니 하트가 클릭된 상태를 useEffect에 저장을 하더라도, useEffect는 비동기적으로 업무를 처리하기 때문에 렌더링이 다 된 이후 fetch를 한다.

이 문제를 해결한 나의 방식을 말해보겠다-!

핵심은 &&연산자이다!

문제 해결과정

참고) 상품의 리스트를 담은 <productList/> 그리고 리스트 안에 담겨있는 상품 하나하나가 <product />이다.

  1. <productList/>내에서 위시리스트 상품 목록 전체를 fetch를 이용하여 전송받는다.
  2. 받은 후 map 을 이용하여 해당 상품의 id값만으로 구성된 배열의 형태를 wishListIds라는 상태값에 저장을 해준다.

// 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));
  };
  1. 그리고 해당 wishListIds를 자식 컴포넌트인 <product />가 포함을 하고 있는지의 여부를 나타낸 값을(불리언 값)을 isHeart라는 변수에 담아서 prop으로 보낸다.
    (즉 isHeart는 상품하나하나가 좋아요가 클릭이 되었는지를 알려준다.
    true = 하트가 색칠이 된 상태)
    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를 전달할 수 있도록 만들어주는 것!!

  1. 자식컴포넌트인 <product />에서 isHeart를 받은 뒤, 하트가 클릭되었는지를 결정해주는 isAdded state의 초기값으로 해당 props를 적어준다.
    const Product = ({ product, direction, isHeart, wishListIds }) => {
     const { id, name, price, image_urls } = product;
     const [isAdded, setIsAdded] = useState(isHeart);
  2. 그리고 거기서 사용자가 다시 좋아요 버튼을 눌렀을 때 상태가 변할 수 있도록 데이터를 전송하는 함수도 만들어준다. (이후 해당버튼에 onClick event로 심어주기! )
    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));
    };
  3. 좋아요 버튼은 isAdded의 값에 따라 칠해져있는 상태가 바뀌도록 조건부렌더링을 해준다.
    <button className="heartBtn" onClick={addToWishList}>
        <i className={isAdded ? 'fas fa-heart' : 'far fa-heart'} />
      </button>

핵심은,
새로고침을 해도 하트 상태를 유지시키고 싶다면 &&연산자를 이용하여 해당 하트 클릭 상태가 저장된다면 prop 으로 자식 컴포넌트에 하트 클릭된 상태(불리언 값)을 보내주고, 받아낸 하트 클릭 상태를 state의 초기값으로 설정을 해주어야 유지가 된다.

비동기처리과정에 대해 확실히 알았다. && 연산자 잘 활용해보자-!!!!

profile
꾸준히 성장하기🦋 https://hyodduru.tistory.com/ 로 블로그 옮겼습니다

0개의 댓글