React에서 useEffect 훅은 정말 자주 이용되는 훅 중에 하나이다.
그만큼 익숙한 훅이었는데 이번에 사용하다가 무한 반복되는 에러를 발견했다.
대표적인 useEffect에서의 무한루프 발생하는 문제는 종속성의 설정이 잘못되었기 때문인데, 최초에 발견했을때 보이는 바로는 문제가 없어보였다.
const mapContainerRef = useRef(null);
const [positions, setPositions] = useState([]);
const api_key = process.env.REACT_APP_API_KEY;
const dispatch = useDispatch();
const allLists = useSelector((state) => state.lists.lists);
const lists = allLists.filter(list => list.user_content_id === 1);
useEffect(() => {
dispatch(fetchLists());
}, [dispatch]);
useEffect(() => {
console.log("fetchLocations");
if (lists.length > 0) {
fetchLocations(lists);
}
}, [lists]);
const fetchLocations = async (lists) => {
...
setPositions(filteredLocations);
...
}
...
}
이게 문제의 코드였다.
분명 lists에 변화가 발생했을때만 useEffect의 콜백 함수가 실행되어야하는데, 마치 조건이 없는 듯이 반복되었다.
여기서 이해할 수 있는 부분은 lists를 생성하는 filter가 호출될때마다 새로운 배열을 만들어내며 참조값이 달라지기에 useEffect가 다시 실행된다는 것이다.
그렇다면 만약 allLists의 데이터 갯수가 10개라면 딱 10번의 호출이 이루어졌어야한다.
게다가 filter 함수는 useEffect가 실행되기 이전에 완료되므로 영향을 받지 않아야한다.
그런데 여기서는 그렇지않고 콜백 함수가 무한 반복되는 현상을 보여줬다.
원인은 이후 코드에 보이는 setPositions였다.
그동안은 운좋게 이러한 상황이 얽히지 않아 문제가 발생하지 않았기에 이상함을 느끼지 못했다.
React는 상태가 업데이트 됨에 따라 랜더링이 결정된다.
그리고 useState의 set은 상태를 새로이 업데이트 시키는 역할을 한다.
즉, useEffect의 fetchLocations가 실행되고, setPositions로 인해 상태가 업데이트되면서 컴포넌트가 리랜더링되고, 그에 따라 useEffect의 종속성 배열의 검토가 이루어진다.
이때 lists의 참조값의 변화를 확인하고 콜백 함수를 실행하는데, 이때 이 콜백 함수가 fetchLocation이므로 선행 과정이 다시 되풀이되는 악순환이 반복된다.
간단히 정리하면 useState의 상태 변화 특성과 filter의 새로운 객체(새로운 참조값), useEffect의 객체 비교방식(얕은 비교)의 상호작용으로 이루어진 에러라는 것이다.
이 중에 리랜더링으로 인한 filter의 불필요한 재실행을 막는 방법을 선택하였다.
useMemo 훅을 이용해 filter가 실행될 필요가 있을 때만 실행되도록 하여 리랜더링이 되어도 참조값이 변하지 않아 무한 루프를 해결할 수 있다.
수정한 코드는 다음과 같다.
...
const lists = useMemo(()=>{ //useEffect에 객체 전달로 인한 리랜더링 방지
return allLists.filter(list => list.user_content_id === 1);
}, [allLists]);
...
이렇게 수정하면 allLists에 변화가 생기지 않는 이상 lists의 값이나 참조값이 변경되지 않는다.
https://memo-code.tistory.com/50
[React] useMemo
useMemo Hook useMemo 훅은 컴포넌트의 성능을 최적화하는데 사용된다.함수의 계산 결과를 메모리에 저장하여 불필요한 재계산을 막아 자원의 낭비를 막는다. useMemo 훅의 사용법은 다음과 같다.const
memo-code.tistory.com
'React' 카테고리의 다른 글
[React] Kakao map api 2 (1) | 2024.11.13 |
---|---|
[React] Kakao map api 1 (1) | 2024.11.08 |
[React] useMemo (0) | 2024.07.24 |
[React] Redux (0) | 2024.04.15 |
[React] Swiper (0) | 2024.03.13 |