(개인적인 기록을 남기기 위한 글입니다.)
리액트 컴포넌트가 가지는 상태에 대한 이해를 돕기 위해 추상적으로 구현한 useState 예제
실제 리액트의 useState를 살펴보면 내부적으로 resolveDispatcher, ReactCurrentDispatcher에 의존성을 가지고 있으며 훨씬 복잡하다.
const useState = (() => {
let _state;
return (initialState) => {
if (_state === undefined) _state = initialState;
const setState = (nextState) => {
_state = nextState;
// ~ 리액트 리렌더링 트리거
// (updateState, updateReducer, basicStateReducer...)
}
return [_state, setState];
}
})();
const MyComponent = () => {
const [state, setState] = useState(0);
setState(100);
if (state === 100) console.log(state);
return;
}
MyComponent(); // 컴포넌트 마운트
MyComponent(); // 컴포넌트 리렌더링 -> 100
클로저를 활용해(useState) 즉시 실행 함수의 지역변수 _state를 자유 변수화
컴포넌트 마운트 시 useState 호출, 컴포넌트 상태 추가 및 초기화 (현재 _state는 undefined로 초기화되어있기 때문에 초깃값으로 전달한 0이 _state에 할당)
새로운 상태 값(100)을 인자로 전달해 setState 호출
자유 변수 _state의 값은 새로운 상태 값(100)으로 업데이트되었지만 현재 컴포넌트 내의 상태 값은 여전히 이전 상태 값(0)을 가리킴 (컴포넌트 내의 state는 const로 선언한 변수일 뿐이다.)
컴포넌트 리렌더링 (예제에서는 컴포넌트 함수를 다시 호출하는 것으로 간략화)
업데이트된 자유 변수 _state를 useState의 반환값으로 전달받음
리렌더링 된 컴포넌트 내의 상태 값은 100이 할당되어 있기 때문에 콘솔 출력