리액트로 프로젝트를 구현하면서 가장 많이 쓰는 함수 중 하나는 단연 useEffect였다. 컴포넌트가 렌더링 되었을 때, 특정 상황에서 특정 작업이 실행될 수 있도록 해주는 역할이다보니 많이 사용할 수 밖에 없었기 때문이었다. 그리고 이 에러는 useEffect를 사용하면서 가장 많이 만났던 에러였다.
useEffect로 리렌더링을 일으키는 로직을 만들었을 때, 리렌더링이 무한하게 일어나지 않도록 제한을 걸어주지 않는다면 에러가 발생한다. (디펜던시 사용.)
위의 문제가 일어나지 않도록 했으나, useEffect 내부에서 리렌더링 조건에 부합하는 동작이 일어났을 때.
const [data, setData] = useState([]);
useEffect(() => {
setData([...]);
}, [data]);
예시) useEffect에 의해서 data의 값이 변화할 때마다 setData가 일어나게 되어있다.
-> 컴포넌트가 렌더링 되었을 때 useEffect가 동작하여 setData가 발생된다.
-> data가 변경되었고, useEffect의 디펜던시dependency array에 들어있는 조건에 따라 useEffect는 setData를 다시 실행시킨다.
-> 무한반복..
페이지가 최초 렌더링 된 직후, useEffect는 위와 같은 이유로 무한하게 동작을 반복하다 브라우저가 뻗어버리는 것이다.
에러의 발생 원리는 단순하지만, 발생 원인은 생각보다는 다양하다. 위에서 언급한 것 이외에 에러 해결을 위해 이것저것 알아보다가 얻은 정보를 여기에 적어보려 한다.
useEffect의 디펜던시에 함수 그 자체를 사용.
-> 페이지가 리렌더링 될 때 컴포넌트 내부에서 선언된 함수는 재선언된다. 값이 변화하였으니 useEffect는 다시 리렌더링을 발생시키고 무한 루프에 빠져버린다.
-> 해결방법 1. 함수 선언부를 useEffect 내부로 이동 시키고 디펜던시를 지워 페이지 렌더링 시 1회만 발동하도록 한다.
-> 해결방법 2. 함수에 useCallback를 적용하여 메모리에 보존하여 함수의 재선언을 막는다. 함수가 재선언되지 않으면 useEffect 디펜던시에 걸리지 않아서 리렌더링도 발생하지 않는다.
디펜던시를 적용하지 않음.
-> useEffect의 디펜던시를 적용할 필요가 없거나 적용할 값이 없을 경우에는 빈 배열을 디펜던시로 적용해주어야한다. 그렇지 않으면 useEffect가 무한 루프에 빠질 수 있다.
이 에러는 원인이 단순한 에러인 만큼 문제를 알아차린 다음부터는 거의 보는 일이 없는 에러였다.
그런데 프로젝트를 진행하면서 사용자가 특정 동작을 수행한 다음 페이지를 리렌더링 시켜야 할 경우에 useEffect를 사용하여 기능을 구현하기 시작하면서 의외로 다시 만나는 일이 많았다.
그 이유는 프론트-백-DB 사이에서 데이터를 주고받고 하며 여러 기능들을 추가하고 발생한 버그를 수정하기 위해 코드를 고친 것이었는데, 머리로는 알고있는데 몸으로는 자꾸 에러가 발생되는 코드를 구현하고 있는 어이없는 상황이 많았다. ㅠ