Rendered more hooks than during the previous render
react
에러를 해결해보자
Error: Rendered more hooks than during the previous render.
문제 상황
밴픽 시뮬레이터를 개발하던 중, 방 입장 시 유효성을 검증하는 커스텀 훅을 만들었다.
function useVerifyBanPickRoom() {
const [isValid, setIsValid] = useState<null | boolean>(null);
useEffect(() => {
const verifyDoc = async () => {
const docSnap = await getDoc(...);
setIsValid(...);
};
verifyDoc();
}, []);
return isValid;
}
그리고 컴포넌트에서 이렇게 사용했다.
function BanPickRoom() {
const isValid = useVerifyBanPickRoom();
if (isValid === null) {
return <Loading />;
}
// isValid 검증 후에만 실행되는 훅들
const someState = useSomeHook();
const anotherState = useAnotherHook();
return <div>...</div>;
}
언뜻 보면 문제가 없어 보인다. 하지만 이 코드는 에러를 발생시킨다.
왜 에러가 발생하는가?
React의 훅은 호출 순서에 의존한다. React는 내부적으로 훅을 연결 리스트로 관리하며, 매 렌더링마다 같은 순서로 훅이 호출될 것이라고 가정한다.
위 코드의 실행 흐름을 따라가보자.
첫 번째 렌더링
useVerifyBanPickRoom()실행useState→ 훅 #1useEffect등록 → 훅 #2isValid는null반환
isValid === null이므로<Loading />반환- 이 시점에서 훅은 2개만 호출됨
두 번째 렌더링 (useEffect 실행 후)
useEffect콜백에서 비동기 검증 완료setIsValid(true)호출 → 리렌더링 트리거useVerifyBanPickRoom()실행useState→ 훅 #1useEffect→ 훅 #2isValid는true반환
isValid === null조건 통과useSomeHook()→ 훅 #3 (새로 등장!)useAnotherHook()→ 훅 #4 (새로 등장!)
React는 이전 렌더에서 2개의 훅을 기억하고 있는데, 갑자기 4개의 훅이 호출되니 혼란에 빠진다.
해결 방법
훅은 항상 컴포넌트의 최상위 레벨에서, 조건문 없이 호출해야 한다.
function BanPickRoom() {
const isValid = useVerifyBanPickRoom();
// 모든 훅을 조건문 위에서 호출
const someState = useSomeHook();
const anotherState = useAnotherHook();
if (isValid === null) {
return <Loading />;
}
if (!isValid) {
return <InvalidRoom />;
}
return <div>...</div>;
}
또는 컴포넌트를 분리하는 방법도 있다.
function BanPickRoomWrapper() {
const isValid = useVerifyBanPickRoom();
if (isValid === null) {
return <Loading />;
}
if (!isValid) {
return <InvalidRoom />;
}
return <BanPickRoom />;
}
function BanPickRoom() {
// 이 컴포넌트는 isValid가 true일 때만 마운트됨
const someState = useSomeHook();
const anotherState = useAnotherHook();
return <div>...</div>;
}