똑같은 삽질은 2번 하지 말자

React vol.23 예상치 못한 랜더링이 일어났던 케이스 본문

카테고리 없음

React vol.23 예상치 못한 랜더링이 일어났던 케이스

곽빵 2024. 11. 4. 17:37

개요

React로 개발을 하면서 예상치 못한 랜더링으로 인해 고생을 했던 케이스들을 모아보았다.

 

 

자식 컴포넌트에서 부모 컴포넌트에서 받은 상태를 변경하는 콜백 함수를 useEffect의 의존성으로 등록하고 실행할 때

 

밑의 코드를 보면 Parent의 handleUpdate가 실행되면 setNumber에 의해 부모 컴포넌트가 리렌더링되고 그로 인해 handleUpdate도 새롭게 재할당된다. 이 재할당으로 인해 자식 컴포넌트에서 onUpdate가 변경됨을 감지 다시 handleUpdate가 실행된다.

import { useEffect, useState } from "react";

type ChildProps = {
  onUpdate: () => void;
};

function Child({ onUpdate }: ChildProps) {
  useEffect(() => {
    onUpdate();
  }, [onUpdate]);
  return <div>test</div>;
}

export default function Parent() {
  const [number, setNumber] = useState(0);

  const handleUpdate = () => {
    setNumber((prev) => {
      return prev + 1;
    });
  };

  return (
    <div>
      <div>{number}</div>
      <Child onUpdate={handleUpdate} />
    </div>
  );
}

 

부모에서 원인을 찾으려다가 헤맸던 케이스다...자식에서 하는일도 면밀히 살펴볼 필요가 있었다. 그리고 부모 컴포넌트 내의 useCallback이나 useMemo를 사용하지 않는 함수나 변수들은 리렌더링 될 때 재할당 되는 것을 제대로 인지하지 못하고 있었다.

다음부턴 조심하자

 

 

컴포넌트 내부에 재랜더링이 일어날 때마다 재할당되는 친구를 리랜더링을 발생시키는 useEffect의 의존성으로 등록하면 무한랜더링이 얼어난다.

 

당연한 현상인데 뭔가 캐치하는데 시간이 좀 걸렸다. 게다가 eslint에서도 경고하고 있었는데 그걸 무시했었다.

코드로 예시를 들자면

const paramArr = searchParams.get('paramArr')?.split(',').map(Number) || [];

useEffect(() => {
  // 리랜더링을 발생시키는 setXXX();
  setXXX();
}, [paramArr]);

 

그래서 paramArr을 useMemo로 랩핑하는걸로 대응했다.

Comments