useState 의 state 는 어떤 코드로 쓰여있나?! - 정리

SeongHyeon Bae·2024년 3월 7일
0

오픈소스 까보기

목록 보기
2/5
post-thumbnail

useState 완전분석(feat. Linked list)

// react/packages/react-reconciler/src/ReactFiberHooks.js
// 926번 줄

function mountWorkInProgressHook(): Hook {
  const hook: Hook = {
    memoizedState: null,

    baseState: null,
    baseQueue: null,
    queue: null,

    next: null,
  };

	// 만약 Hook이 없으면 첫번째 값을 할당
  if (workInProgressHook === null) {
    // This is the first hook in the list
    currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
  } else {
    // workInProgress를 한칸 옆으로 이동시킴
    workInProgressHook = workInProgressHook.next = hook;
  }
  return workInProgressHook;
}
  • memoizedState 는 상태가 변한 후 최종적으로 기억되는 값
  • next 는 링크드리스트 처럼 연결되어 있다. 이 값은 다음 훅을 할당될 키값 이다.
  • fiber는 hook이 링크드리스트로 연결되어 있다.

mountStateImpl

//1750 줄
function mountStateImpl<S>(initialState: (() => S) | S): Hook {
  const hook = mountWorkInProgressHook(); // 여기서 hook을 넘겨줌
  if (typeof initialState === 'function') {
    const initialStateInitializer = initialState;
    // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
    initialState = initialStateInitializer();
    if (shouldDoubleInvokeUserFnsInHooksDEV) {
      setIsStrictModeForDevtools(true);
      // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
      initialStateInitializer();
      setIsStrictModeForDevtools(false);
    }
  }
  hook.memoizedState = hook.baseState = initialState;
  const queue: UpdateQueue<S, BasicStateAction<S>> = {
    pending: null,
    lanes: NoLanes,
    dispatch: null,
    lastRenderedReducer: basicStateReducer,
    lastRenderedState: (initialState: any),
  };
  hook.queue = queue;
  return hook;
}
  • 이곳에서 initialState가 함수이면 함수를 실행시킨 값을 전달함을 알 수 있다.

Hook에서 왜 queue 객체를 사용할까?

const queue: UpdateQueue<S, BasicStateAction<S>> = {
    pending: null,
    lanes: NoLanes,
    dispatch: null,
    lastRenderedReducer: basicStateReducer,
    lastRenderedState: (initialState: any),
  };
  • pending은 업데이트 될 다음 상태를 나타낸다.
  • dispatch는 queue에서 추가로 들어갈 수 있도록 도와주는 것
function mountState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
  const hook = mountStateImpl(initialState);
  const queue = hook.queue;
  const dispatch: Dispatch<BasicStateAction<S>> = (dispatchSetState.bind(
    null,
    currentlyRenderingFiber,
    queue,
  ): any);
  queue.dispatch = dispatch;
  return [hook.memoizedState, dispatch];
}
  • dispatch는 이전에 선언했던 queue가 바인딩 되고 있다.
  • 이 dispatch는 외부로 노출되고 있다. → 이것이 결론적으로 setState
profile
FE 개발자

0개의 댓글