똑같은 삽질은 2번 하지 말자
React vol.23 예상치 못한 랜더링이 일어났던 케이스 본문
개요
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