Github Actions로 배포 자동화를 하는 도중 아래의 eslint 오류가 엄청 많이 떴다.
React Hook useEffect has missing dependencies: 'deleteItemFromCart', 'item'
Either include them or remove the dependency array react-hooks/exhaustive-deps
useEffect(() => {
item.quantity = quantityInput; // 상품의 개수나
item.price = milesTicketInput; // 마일티켓 개수가 변경되면 업데이트 해준다.
if (item.quantity === 0) { // 개수가 0개가 될 경우에는 카트에서 삭제한다.
deleteItemFromCart();
}
}, [quantityInput, milesTicketInput]); // 개수와 마일티켓 input의 값이 변경될 때마다 useEffect 실행
찾아보니 이 경고는 useEffect 안에서 useEffect의 의존성 배열에 정의되지 않은 변수를 사용하기 때문에 발생하는 것이다.
즉, useEffect 안에서 deleteItemFromCart
과 item
이라는 변수를 사용하는데, 의존성 배열에 위의 두 변수가 추가되어있지 않다는 것이다.
따라서 해당 경고를 해결하기 위해서는 useEffect 함수의 의존성 배열에 deleteItemFromCart
와 item
을 추가하거나, 해당 변수를 사용하지 않는 방법 중 하나를 선택해야 한다.
deleteItemFromCart
와 item
을 useEffect의 의존성 배열에 추가한다.
useEffect(() => {
item.quantity = quantityInput;
item.price = milesTicketInput;
if (item.quantity === 0) {
deleteItemFromCart();
}
}, [quantityInput, milesTicketInput, item, deleteItemFromCart]);
deleteFromCart
함수를 useEffect 안으로 옮겨준다. 이렇게 하면 deleteFromCart
를 의존성 배열에 추가할 필요가 없다.
useEffect(() => {
const deleteItemFromCart = () => {
setCart(cart.filter((cartItem) => cartItem.UniqueEntryID !== item.UniqueEntryID));
}
// ...
}, [quantityInput, milesTicketInput, item]);
혹은 eslint-disable-next-line react-hooks/exhaustive-deps
주석을 추가하면 해당 코드 라인에서만 의존성 배열 경고를 무시할 수 있다. 위와 같이 다만, 이 방법은 의존성 배열이 불완전한 상태로 남아있을 수 있으므로 주의해서 사용해야 한다.
useEffect(() => {
// 생략...
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
나는 1번 방법으로 해결하는 것으로 선택했다. 1번처럼 코드를 수정하고 다시 빌드를 했더니 또 다른 경고가 발생했다.
Line 14:8: The 'deleteItemFromCart' function makes the dependencies of useEffect Hook (at line 25) change on every render.
To fix this, wrap the definition of 'deleteItemFromCart' in its own useCallback() Hook react-hooks/exhaustive-deps
해석하면 useEffect의 의존성 배열에 있는 deleteItemFromCart
함수가 매 렌더링마다 useEffect의 종속성을 변화시킨다는 것이다.
deleteItemFromCart
함수는 변하지 않는데 왜 종속성을 변화시키지? 라고 생각할 수 있다.
하지만 JavaScript는 참조 동등성(referential equality)을 기반으로 작동하기 때문에, 객체(함수 또한 객체)는 메모리에서 동일한 객체를 참조하는 경우에만 서로 동일하다고 여긴다.
그래서 JavaScript는 매 렌더링마다 새롭게 생성되는 deleteItemFromCart
함수가 항상 다르다고 받아들여 useEffect를 실행하는 것이다.
이를 해결하려면 해당 함수를 useCallback으로 감싸면 된다.
const deleteItemFromCart = () => {
setCart(cart.filter((cartItem) => cartItem.UniqueEntryID !== item.UniqueEntryID));
};
const deleteItemFromCart = useCallback(() => {
setCart(cart.filter((cartItem) => cartItem.UniqueEntryID !== item.UniqueEntryID));
}, [cart, item.UniqueEntryID, setCart]);
이때, useCallback의 의존성 배열 안에 해당 함수에서 사용하는 변수들을 넣어줘야 한다.
넣어주지 않으면 어떻게 되냐고? (나도 알고 싶지 않았다..)
아래와 같이 의존성 오류가 또 발생할 수 있으니, useCallback에서 사용하는 변수와 함수들을 의존성 배열에 넣어줘야 한다.
Line 16:5: React Hook useCallback has missing dependencies: 'cart', 'item.UniqueEntryID', and 'setCart'.
Either include them or remove the dependency array. If 'setCart' changes too often,
find the parent component that defines it and wrap that definition in useCallback react-hooks/exhaustive-deps
Fix the "Function makes the dependencies of useEffect Hook change on every render" warning in React
저도 무한 렌더링 걸렸을 때 지은님이랑 다른 방법으로 해결했는데, useCallback으로 해결 잘하신거같네요 대단합니다