리액트 컴포넌트 분리와 리렌더링 실수

MM·2024년 9월 16일

make it worth

목록 보기
8/10
post-thumbnail

특정 컴포넌트의 반복적 리렌더링

특정 컴포넌트가 반복적으로 리렌더링된다. 이유가 뭘까.

원인

  const { phase } = usePaperbookModalStore(
    (state: PaperbookModalStoreType) => state
  );
  const { memberCode } = useUserStore((state: UserStoreType) => state);
  const { setTotalPurchasedCnt, purchasePage, setPurchasePage } =
    usePaperbookModalStore((state: PaperbookModalStoreType) => state);

  const [bookSetList, setBookSetList] = useState(null);

const PurchasedListView = () => {
  console.log("리렌더링?");
  if (!Array.isArray(bookSetList)) return <Loading />;
  if (Array.isArray(bookSetList) && bookSetList.length === 0)
    return <NoneImage />;

  return (
    <PurchaseList
      bookSetList={bookSetList}
      getPurchaseList={getPurchaseList}
    />
  );
};

return (
  <div className="purchase_list">
    <PurchasedListView />
    {phase == "eachSetPhase" && <EachSet />}
  </div>
);

리턴문에 삼항연산자가 많이 들어가는 게 싫어서 따로 컴포넌트화해 관리하고 있었더니,

phase가 바뀔 때마다 PurchasedListView가 같이 리렌더링되고 있었다.

해결

  const { phase } = usePaperbookModalStore(
    (state: PaperbookModalStoreType) => state
  );
  const { memberCode } = useUserStore((state: UserStoreType) => state);
  const { setTotalPurchasedCnt, purchasePage, setPurchasePage } =
    usePaperbookModalStore((state: PaperbookModalStoreType) => state);

  const [bookSetList, setBookSetList] = useState(null);

return (
  <div className="purchase_list">
    {Array.isArray(bookSetList) ? (
      bookSetList.length ? (
        <PurchaseList
          bookSetList={bookSetList}
          getPurchaseList={getPurchaseList}
        />
      ) : (
        <NoneImage />
      )
    ) : (
      <Loading />
    )}
    {phase == "eachSetPhase" && <EachSet />}
  </div>
);

컴포넌트를 풀어서 다시 리턴문에 넣어주니 리렌더링이 발생하지 않았는데…

phase가 바뀌면 해당 컴포넌트 전체가 리렌더링되니 어느 쪽이던 똑같이 다 리렌더링되어야 하는 거 아닌가?

💡 PurchaseListTab 컴포넌트가 리렌더링될 때마다 return 문이 다시 평가됩니다. 하지만 중요한 점은 PurchaseList의 렌더링 여부가 bookSetList의 상태에만 의존한다는 것입니다.


즉, bookSetList가 변경되지 않으면, phase의 변경만으로는 PurchaseList가 다시 렌더링되지 않습니다.
대신 phase == "eachSetPhase" && <EachSet /> 부분만 조건에 따라 렌더링됩니다.

→ 그러니까 phase가 변경되어 리렌더링이 발생하면, 리렌더링을 발생시킨 원인(phase)과 관련 있는 컴포넌트들만 골라 리렌더링 되는 것.

-> 리액트 리렌더링 관련해서 아주 기본적인 내용인데, 새삼 이렇게 깨닫다...

→ ..근데 그럼 기존 컴포넌트에 useCallback을 줘도 되지 않을까?🤔 시도.

→ 리렌더링되지 않는다! 해결! 👍👍

profile
중요한 건 꺾여도 그냥 하는 마음

0개의 댓글