"react-hooks/exhaustive-deps" 규칙은 효과 후크에 누락된 종속성이 있을 때 경고를 띄운다. 경고를 없애려면 useEffect 내부의 함수 또는 변수 선언을 이동하고 렌더링할 때마다 변경되는 배열 및 개체를 메모화하거나 규칙을 비활성화해야 한다.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ 객체와 배열은 참조자료형이기 때문에 내부의 값이 변하지 않더라도 렌더링이 될 때마다 다른 값인 것으로 간주된다.
const obj = {country: 'Germany', city: 'Hamburg'};
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// ⛔️ React Hook useEffect has a missing dependency: 'obj'.
// Either include it or remove the dependency array. eslintreact-hooks/exhaustive-deps
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
문제는 useEffect 내부에서 obj
변수 를 사용 하고 있지만 종속성 배열에는 포함되지 않았다는 것이다.
오류에 대한 가장 확실한 해결책은 종속성 배열에 obj
를 추가하는 것이다.
그러나 이 경우 객체와 배열이 JavaScript에서 참조로 비교되기 때문에 오류가 발생하게 된다.
obj
는 리렌더링 될 때 동일한 키-값 쌍을 가진 객체이지만 매번 메모리의 다른 reference를 가리키므로 동등성 검사에 실패하고 무한 렌더링이 발생한다.
이 때 경고를 피하는 방법중 하나는 한 줄 또는 전체 파일에 대한 eslint 규칙을 비활성화 하는 것이다.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
const obj = {country: 'Germany', city: 'Hamburg'};
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
종속성 배열 윗 줄에 추가된 주석은 한 줄에 대한 react-hooks/exhausting-deps
규칙을 비활성화한다.
💡 후크에 빈 배열이 두 번째 매개변수로 전달 되면 useEffect구성 요소가 마운트될 때만 호출된다.
다른 해결책은 변수나 함수의 선언을 useEffect
내부로 이동하는 것이다.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
useEffect(() => {
// 👇️ 참조 자료형의 데이터를 useEffect 내부에서 선언하기
const obj = {country: 'Germany', city: 'Hamburg'};
setAddress(obj);
console.log('useEffect called');
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
useEffect
내부에서 개체에 대한 변수를 선언하였다.
hook이 더 이상 외부 개체에 대한 종속성을 가지지 않기 때문에 이렇게 하면 경고가 제거된다.
드물게 사용할 수 있지만 알고 있으면 좋은 또 다른 솔루션은 함수 또는 변수 선언을 구성 요소 밖으로 옮기는 것이다.
import React, {useEffect, useState} from 'react';
// 👇️ 함수나 변수의 선언을 컴포넌트 외부로 옮기기
const obj = {country: 'Germany', city: 'Hamburg'};
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
이렇게 하면 구성 요소가 다시 렌더링 될 때마다 변수가 다시 생성되지 않기 때문에 도움이 될 수 있다.
변수는 매 렌더링마다 메모리의 동일한 위치를 가리키므로 useEffect
종속성 배열에서 변수를 추적할 필요가 없다.
이를 대체할 수 있는 솔루션은 memoized 값을 얻기 위해 useMemo hook을 사용하는 것이다.
import React, {useMemo, useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ memoized된 값 가져오기
const obj = useMemo(() => {
return {country: 'Germany', city: 'Hamburg'};
}, []);
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// 👇️ 안전하게 종속성 배열에 추가할 수 있다.
}, [obj]);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
렌더링 간에 변경되지 않는 메모화된 값을 얻기 위해 useMemo
hook을 사용했다.
💡
useMemo
는 메모할 값과 종속성 배열을 매개변수로 반환하는 함수를 사용한다. 이는 종속성 중 하나가 변경된 경우에만 메모된 값을 다시 계산한다.
함수로 작업하는 경우 useCallback
를 사용하여 렌더링 간에 변경되지 않는 메모화된 콜백을 가져올 수 있다.
import React, {useMemo, useEffect, useState, useCallback} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ memoized된 콜백함수를 가져온다.
const sum = useCallback((a, b) => {
return a + b;
}, []);
// 👇️ memoized된 값을 가져온다.
const obj = useMemo(() => {
return {country: 'Germany', city: 'Santiago'};
}, []);
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
console.log(sum(100, 100));
// 👇️ 안전하게 종속성 배열에 추가할 수 있다.
}, [obj, sum]);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
useCallback
은 인라인 콜백 함수와 종속성 배열을 사용하고 종속성 중 하나가 변경된 경우에만 변경되는 메모화된 버전의 콜백함수를 반환한다.