패스잇
프론트엔드 개발 · 심화

함수형 컴포넌트는 클로저를 기반으로 동작합니다. 이로 인해 발생하는 'stale closure(오래된 클로저)' 문제가 무엇이며, setInterval이나 이벤트 구독 안에서 state를 참조할 때 왜 의도치 않은 값이 보이는지, 그리고 이를 해결하는 방법을 설명해주세요.

힌트 · 각 렌더가 자신만의 props/state 스냅샷을 캡처한다는 점과 의존성 배열·ref를 통한 해결 관점에서 접근하세요.

클로저상태(state)재렌더링useRefuseEffect

모범답안

함수형 컴포넌트는 렌더링될 때마다 새로운 함수 스코프를 생성하고, 이 스코프는 해당 렌더링 시점의 props와 state 값을 '캡처'합니다. 이것이 바로 클로저의 동작 방식입니다.

'Stale closure' 문제는 이 캡처된 오래된 스코프가 계속 유지되어 발생하는 현상입니다. 예를 들어, setInterval이나 이벤트 리스너 안에서 state 값을 참조할 때, 컴포넌트가 재렌더링되어 state가 업데이트되었더라도, setInterval이나 이벤트 리스너는 처음 생성될 때의 오래된 state 값을 계속 참조하게 됩니다. 그래서 의도치 않게 이전 값이나 예상치 못한 값이 보이는 것이죠.

이 문제를 해결하는 방법은 크게 두 가지입니다.

첫째, useEffect의 의존성 배열을 활용하는 것입니다. useEffect의 두 번째 인자인 의존성 배열에 state나 props를 명시하면, 해당 값이 변경될 때마다 useEffect 내부의 함수가 다시 실행되어 최신 값을 참조하게 됩니다. 하지만 setInterval처럼 주기적으로 실행되어야 하는 경우, 의존성 배열에 모든 state를 넣으면 너무 자주 클린업되고 다시 설정되어 성능 문제가 발생할 수 있습니다.

둘째, useRef를 사용하는 것입니다. useRef는 컴포넌트의 생명주기 동안 값이 유지되면서도, 값이 변경되어도 컴포넌트를 재렌더링하지 않습니다. 따라서 setInterval이나 이벤트 리스너 안에서 최신 state 값을 참조하고 싶을 때, 해당 state를 useRef에 저장해두고 useRef.current 값을 참조하면 stale closure 문제를 피할 수 있습니다. useEffect 안에서 useRef를 업데이트하고, setInterval 등에서는 useRef를 참조하는 방식으로 구현하면 됩니다.

읽었다면, 이제 직접 답해볼 차례예요

패스잇 앱에서 이 질문에 말로 답하면 AI가 꼬리질문까지 이어가며 1:1 코칭합니다.

함께 보는 React 면접 질문

← React 면접 질문 전체 보기