챌린지 수업을 들으면서 라이프 사이클에 대해서 배우면서 나왔던 질문에 대해서 정리를 하려고 한다.
질문에 대한 내용은 아래와 같다.
const [state, setState] = useState(0);
console.log(state); // (1)
useEffect(() => {
setState(1);
return () => {
console.log(state); // (2)
};
}, [state]);
위 코드를 실행하면 0 1 0 1이 나오는데 그 원리에 대해서 이해가 안가서 동작 원리에 대한 질문이었다.
처음 코드를 얼추 보자마자 무한 재귀로 진행될 것 같았다. useEffect의 dependency는 state의 값의 변화에 따라서 업데이트 될 때 마다 실행을 하는데 안에서는 setState로 state 변경을 시도하기 때문이다.
하지만 얼마안가 다행히 재귀가 아니라는 것은 금방 판단할 수 있었다.
setState를 당연하게도 안에 함수를 넣어서 이전 값을 넣어서 갱신하는 것이라고 생각했는데 그게 아니라 특정 값 1을 넣고 있으니 어느 순간 더 이상 useEffect가 실행되지 않기 때문이다.
일단 처음에 생각했던 무한 재귀 호출로 프로그램이 종료되지 않을 것 같다라는 것이 판단을 했으니 0 1 0 1으로 출력되는 원인에 대해서 고민을 했다.
오케이! 여기까지는 이해를 했다. 이어서 보자면
이 부분이 최대 난관이다. 이때 실행하는 setState가 애매했다. setState에는 현재 이전 값과 동일한 1의 값이 들어간다. 여기서 변경을 일으킬까?
확실한 구분을 위해서 코드를 아래처럼 변경을 했다. 그리고 브라우저 상에서 어떻게 동작하는지 확인한 결과 다시 한번 1번 로그가 실행이 됐다.
이것만 보면 마치 setState를 실행 시킨다면 컴포넌트를 무조건 다시 한번 호출되는 것 처럼 보인다.
setState를 할 당시에 state는 이미 값이 1이고 이는 원시값이기 때문에 둘의 값은 같고 랜더링이 일어나면 안된다. 그런데 만약 setState에 같은 값이 들어가도 변경이 발생한다면 불변성을 유지하면서 값을 넣을 필요가 없는 것이 아닌가?
리액트 공식문서를 확인하였다. 공식문서 상에서 호출되기는 하지만 코드에 영향을 미치지 않는다고 한다. 심도있게 배운 것 같아 정말 기분이 좋았다. 오늘 잠 못잘 뻔 했는데 정말 다행이다.
Object.is 비교에 의해 결정된 대로 사용자가 제공한 새 값이 현재 상태와 동일하다면, React는 컴포넌트와 그 자식들을 다시 렌더링하지 않습니다. 이것은 최적화입니다. 경우에 따라 React가 자식을 건너뛰기 전에 컴포넌트를 호출해야 할 수도 있지만, 코드에 영향을 미치지는 않습니다.
이걸 다 정리하는 빛진호... 갓진호..