2025 04 15
2025-04-15¶
Stale Closure¶
참고: https://handhand.tistory.com/264
참고: https://seongry.github.io/2022/06-05-hooks-dependencies-and-stale-closures/
- 개요
- Stale Closure: 상태 값에 변화가 발생해도 감지하지 못하고 예전 값을 바라보는 상태
- Closure: 생명주기가 끝난 외부함수의 변수를 참조하는 함수
- 함수는 자신이 선언될 때의 환경 (변수/상수)를 함께 기억
- useEffect와 같은 훅에서도 의존성 배열에 refresh 해야하는 것을 넘겨주자.
- 리액트 컴포넌트는 새 props/state로 렌더링시 함수 내부 클로저도 최신 상태로 반영하지만,
- useCallback/useMemo 등을 쓸 때 의존성 배열 잘 못 관리하면 함수가 계쏙 같은 클로저 사용함
- state closure 상황
- 무한 스크롤에서 그 다음 페이지를 불러오지 못하는 문제 발생
- useCallback에 정의된 함수가 dependency array 항목에 따라 최신화되는데, 최신화되는 조건의 누락시 발생
- 정의된 함수는 바뀌지 않으니 하염없이 같은 함수만 호출할 수 있음
- 함수가 생성될 때 사진을 찍는다고 생각하자. 함수 호출은 그냥 사진을 다시 가져오는거고.
-
코드
const lastElementRef = useCallback( (node: HTMLLIElement) => { if (loading) return; if (observerHasNext.current) observerHasNext.current.disconnect(); observerHasNext.current = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && hasNext) { getList(service, currentPage + 1, 10, targetType, keywordType, keyword); } }); if (node) observerHasNext.current.observe(node); }, [hasNext] );- 다음과 같이 콜백 함수가 hasNext에 대해서만 최신화됨.
- 이러다 보니 fetch 안의 여러 변수들의 값이 이미 정의된 대로 주구장창 사용중 (stale closure)
- dependency array에 getList 함수에 들어갈 변수들을 함께 정의해두자.
- 다음과 같이 콜백 함수가 hasNext에 대해서만 최신화됨.