카테고리 없음
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로 랩핑하는걸로 대응했다.