fetch뒤에 바로 setState를 하면 메모리 누수 문제가 생길 수 있다.
만약 서버에서 응답이 오는 시간이 길어지는 사이에 사용자가 다른 작업을 하면 컴포넌트가 unmount될 수 있다. 이때 컴포넌트는 사라지지만 요청은 여전히 대기 중일 것이다. 그리고 요청이 도착하고 setState에 값을 업데이트 하려고할 때 아래와 같은 메모리 누수와 관련한 경고가 뜰 수 있다.
Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
따라서 컴포넌트가 unmount가 될 경우에 요청이 늦게와도 조건문으로 setState를 업데이트하는 것을 방지할 수 있다.
const [userInfo, setUserInfo] = useState([]);
const [reviewInfo, setReviewInfo] = useState([]);
const [likesInfo, setLikesInfo] = useState([]);
useEffect(() => {
let isComponentMounted = true;
const fetchData = async () => {
const userData = await axios.get(
`${process.env.REACT_APP_API_URL}/users`
);
const likesData = await axios.get(
`${process.env.REACT_APP_API_URL}/likes`
);
const reviewData = await axios.get(
`${process.env.REACT_APP_API_URL}/reviews`
);
if (isComponentMounted) {
setUserInfo(userData.data.data);
setLikesInfo(likesData.data.data);
setReviewInfo(reviewData.data.data);
}
};
fetchData();
return () => {
isComponentMounted = false;
};
}, []);
또는 http fetch 요청을 취소하는 AbortController
를 사용할 수 있다. AbortController
는 fetch
작업을 취소할 수있도록 해주는 인터페이스다.
axios 요청을 취소하는 건 아래와 같이 진행된다. 하지만 위와 동일하게 mount되었는지 안되어있는지를 변수에 두어서 따로 확인해야한다.
//useEffect안에 넣어주고
let unmounted = false;
let source = axios.CancelToken.source();
//cleanup에 cancel을 넣어준다.
unmounted = true;
source.cancel("Cancelling in cleanup");
unmounted (마운트 해제)는 요청이 취소되지 않았거나 일부 다른 작업을 취소할 수 없는 경우 필요하다.
네트워크 호출이 반환되기 전에 네트워크 속도를 늦추고 구성 요소를 마운트 해제하면 unmounted된 컴포넌트에 대해 상태를 업데이트할 수 없다
는 오류가 뜨는 것이다.
변수로 마운트가 되었는지 아닌지 관리해주면서 setState를 업데이트 해야지 위와 같은 오류를 막을 수 있다.