유튜브 영상을 보다가 아래 문제를 마주하게 되었다. 유튜버인 개발자는 신입 면접을 볼 때 아래 문제로 기본기를 파악한다고 해서 내가 맞출 수 있는지 풀어보았는데, 아래 문제에서 틀리고 말았다. 근데 틀린것도 틀린거지만 아무리 보고 설명을 들어도 이해가 가지 않았다😱
당황도 잠시, 내가 모르는 게 뭔지 알았으니 배워보자!
콘솔에 어떻게 나올까 ?
export function App() {
const [state, setState] = useState(0);
console.log(state)
useEffect(() => {
setState(1)
},[state])
return <div className='App'></div>
}
첫번째 문제는 정답을 맞췄다!
코드는 위에서 부터 아래로 실행이 되므로 처음 콘솔에는 state의 초깃값인 0이 나오고, useEffect 함수는 컴포넌트가 렌더링 된 후에 동작하는데, useEffect 함수 내부에서 setState 로 state 값을 1로 변경 해주기 때문에 코드가 위에서 다시 실행 되어 그 다음 콘솔에 1이 찍힌다. 근데 useEffect 에서 의존성 배열에 state 를 넣어주었기 때문에, state가 0 에서 1로 변경되었기 때문에 다시 렌더링 되고, state 의 현재값인 1이 콘솔에 찍힌다. 그래서 콘솔에 차례대로 0 1 1 이 찍힌다.
정답 0 1 1
첫번째 문제의 응용 버전이다.
다음 코드에서는 콘솔에 어떻게 찍힐까?
나는 여기서 문제를 틀렸었다.
export function App() {
const [state, setState] = useState(0);
console.log(state)
useEffect(() => {
setState(1)
return () => {
console.log(state)
}
},[state])
return <div className='App'></div>
}
나는 0 1 1 이 나올거라 생각했다. 순서대로 0 1 이 찍힌 다음에 클린업 함수가 실행 되면서 state 의 최신값인 1 이 찍힐 거라 생각했다. 허나 정답은 0 1 0 1 이다.😲
정답 0 1 0 1
왜 그럴까? 설명을 들어도 이해가 가지 않았다. 그말은 즉슨 내가 useEffect cleanup 함수에 대해서 잘모르고 있다는 뜻이었다ㅠㅠ
리액트는 브라우저가 페인팅을 하고 난 다음에 effect 를 실행합니다. 그게 effect 클린 함수건 effect 함수 자체건 말이죠. 이렇게 해야 리액트가 브라우저의 렌더링을 방해하지 않습니다.
아하!? 위에 글을 읽고 조금 감을 잡았다.
컴포넌트가 렌더링 될때 모든 함수는 (이벤트 핸들러, 이펙트, 타임아웃 등) 렌더가 호출될 때 정의 된 props 와 state 값을 잡아두고 있다. 이말은 즉슨 클린업 함수는 최신 state 값을 읽지 않는다. 클린업 함수가 정의된 시점의 값을 읽는다.
그러니까 처음 state 값인 0 이 클린업 함수의 콘솔에 찍히고, 그 다음에 1이 찍힌 것이다...!
이렇게 작동 하는 이유는 빠르게 화면에 보여지게 하도록 하기 위해서이다. 새로운 state 값을 업데이트 해주고 난 다음에야 이전 값들을 차례대로 클린업 되는 것이다.
지금까지 클린업 함수는 컴포넌트가 언마운트 될때 실행 된다는 것만 알았지 작동 방법에 대해서는 너무 무지했다.