커스텀 훅으로 json-server에 있는 데이터를 가져오려는데 이 훅을 컴포넌트에 쓰면 다음과 같은 에러가 발생한다.
VM132648:1 Warning: Cannot update a component (
TodoList
) while rendering a different component (TodoList
). To locate the bad setState() call insideTodoList
, ...
훅 코드는 다음과 같다.
import { useEffect, useState } from 'react';
import { T_todoState, fetchTodo } from '../redux/modules/todo';
import { useAppDispatch } from '../redux/config/configStore';
import { getTodoDB } from '../axios/dbApi';
const useFetchTodoDB = (): void => {
const [todoDB, setTodoDB] = useState<T_todoState>([]);
const dispatch = useAppDispatch();
useEffect(() => {
const getData = async (): Promise<void> => {
try {
const db = await getTodoDB();
setTodoDB(db.data.database.todo);
} catch (error) {
console.log(error);
}
};
getData();
}, []);
if (todoDB.length > 0) {
dispatch(fetchTodo(todoDB));
}
return;
};
export default useFetchTodoDB;
이 경고는 useFetchTodoDB
훅에서 상태 업데이트를 수행하는 동안 컴포넌트 렌더링이 진행되어 생기는 문제다.
useEffect
훅은 컴포넌트가 렌더링된 이후에 비동기적으로 데이터를 가져오는데 사용되는 것이 좋다.
그러나 useFetchTodoDB
훅은 렌더링 시에 상태 업데이트를 수행하고 있기 때문에 경고가 발생하는 것이다.
렌더링 중에 상태를 업데이트하는 것은 React
에서 권장되지 않는 방식이므로, 이런 상황에서는 아래와 같이 useEffect
를 사용하여 상태 업데이트를 따로 처리하자.
useEffect
를 사용하여 코드를 작성하면 해당 경고가 사라진다.
const useFetchTodoDB = (): void => {
(코드 생략)...
useEffect(() => {
if (todoDB.length > 0) {
dispatch(fetchTodo(todoDB));
}
}, [todoDB, dispatch]);
return;
};
export default useFetchTodoDB;
useEffect
는 비동기 함수가 아닌데도 불구하고, 해당 에러가 사라지는 중요한 이유는 react
에서 useEffect
는 모든 컴포넌트들이 렌더링이 완료된 후에 실행되는 함수이기 때문이다.