UseEffect를 수정하던 도중 아래와 같은 문제가 발생하였다. 이에 대해 해결을 위해 공식문서와 구글링을 하던 중 exhaustive-deps-warning이 나 뿐만이 아니라 다른 분들도 매우 자주 겪는 warning error이며, 다른 말로 나 뿐만 아니라 많은 사람들이 자주 겪고 헷갈려하는 문제라는 사실을 알 수 있었다.
이에 이번 글을 통해 exhaustive-deps 규칙에 대해 알아보며 어떤 부분에서 많은 사람이 헷갈려하는지, 그리고 이에 대한 해결책은 무엇인지에 대해 알아보고자 한다.
React Hook useEffect has a missing dependency: 'xxx'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)
useEffect의 의존성 배열에서 발생할 수 있는 문제를 해결하기 위해 React 팀이 exhaustive-deps 규칙을 제안하여 등장하게 된 개념이다.
이에, exhaustive-deps 규칙 등장 이후, React 내에서 useEffect의 의존성 배열에 모든 의존성을 명시적으로 포함시키라고 권장되고 있다.
exhaustive-deps는 React의 useEffect, useCallback과 같은 훅에서 사용되는 의존성 배열과 관련된 경고로, 주로 두 가지 상황에서 발생한다.
아래 코드는 잘못된 의존성 참조를 보여주는 짧은 예이다.
아래 코드에서 addCount 함수는 num 값을 참조하지만, useEffect의 의존성 배열에 포함되지 않는다. 이로 인해 num 값이 변경되어도 useEffect는 반응하지 않게 되는 문제가 발생하게 된다.
function App() {
const [count, setCount] = useState(0);
const [num, setNum] = useState(0);
const addCount = () => {
setCount(c => c + 1);
console.log(`num: ${num}`);
}
useEffect(() => {
const timerId = setInterval(addCount, 1000);
return () => clearInterval(timerId);
}, []);
// ...
}
useCallback Hook을 사용하면 함수를 재사용할 수 있으며, exhaustive-deps 규칙을 준수할 수 있다.
아래 코드를 살펴보면, useCallback을 사용해 addCount 함수는 num 값이 변경될 때만 재생성되며, useEffect의 의존성 배열에 올바르게 반영되는 모습을 살펴볼 수 있다.
const addCount = useCallback(() => {
setCount(c => c + 1);
console.log(`num: ${num}`);
}, [num]);
useCallback의 장점
- 성능 최적화: 불필요한 함수 재생성을 방지하여 성능을 개선한다.
- 메모리 절약: 재생성되지 않는 함수는 메모리에 캐시되어 재사용된다.
- 의존성 관리: useEffect와 함께 사용할 때 의존성 관리가 명확해진다.
함수 내부에서 직접 스테이트를 참조하는 대신, 파라미터를 통해 값을 전달하는 방법도 있다. 이렇게 하면 의존성 관리가 더욱 명확해지며, useEffect가 예상대로 동작하게 된다.
아래 코드를 통해 파라미터를 활용한 예를 확인 가능하다.
const addCount = (log) => {
setCount(c => c + 1);
console.log(log);
};
useEffect(() => {
const timerId = setInterval(() => addCount(`num ${num}`), 1000);
return () => clearInterval(timerId);
}, [num]);
이번 글을 통해 react-hooks/exhaustive-deps 규칙에 대해 알아보며, React에서 의존성을 관리하는 것이 얼마나 중요한지 다시 한 번 깨달을 수 있었다.
특히, React에서 의존성 배열을 올바르게 관리하는 것이 때로는 복잡하고, 헷갈리게 여겨질 수 있으나, 이러한 규칙을 준수함으로써 React의 성능을 최적화하고, 예상치 못한 버그를 방지할 수 있다는 점을 깨달을 수 있었다.
앞으로도 코드를 수정하고 리펙토링하면서 react-hooks/exhaustive-deps 규칙에 대해 항시 숙지하고, 만일 다음 에러를 만나게 되더라도 오늘의 학습과 깨달음을 바탕으로 에러를 효과적으로 대처해 나가보자.