React useState분석 (Linked list)

HughKim·2024년 5월 13일
0

react deepdive

목록 보기
2/3
post-thumbnail

시작에 앞서 linked list란 무엇일까?

여러개의 node가 서로 연결되어 있다.
하나의 node에는 node value와 pointer to the next node가 있고 next node는 다음 node을 가리키게 된다.


mountWorkInProgressHook

hook객체

  • hook.memoizedState 마지막에 얻은 state값
  • hook.next다음 hook을 가리키는 pointer(hook은 linked list에 저장)
  • hook.queue hook을 호출할 때마다 update객체를 linked list로 구현한 queue에 저장
  • hoook은 배열로 설명할 수 있지만, 실제코드에서는 linked list로 구현된다.

workInProgressHook

작업중인 hook이 null일 경우 첫번째 hook아니면 그 다음 hook으로 추가한다.
fiber.memoizedState에 firstWorkInProgressHook할당 -> 컴포넌트와 hook(linked list)연결
workInProgressHookdms tail poiner

mountState

initialState가 함수면 초기값을 할당
hook.memoizedState에 initialState할당

setState의 state update과정

dispatchAction함수

  • 조건문은 render phase update OR idle update구분
    - update객체 생성
    - expiration Time
    - action(setState()인지)
    - next : null
    - eagerReducer : null
    - eagerState : null
    update를 queue에 저장( circular linked list )

  • 불필요한 렌더링이 발생하지 않도록 최적화
    - Work스케줄링 X(현재 컴포넌트의 업데이트로 인해)
    - action의 결과값 === 현재 상태값
    두가지 조건 모두 만족할 경우 함수 return(실행중지)
    update를 적용하기 위해 Work를 scheduler에 예약(scheduling)

setState를 호출하는 2가지 경우

  1. idle
  2. render phase

currentlyRenderingFiber

currentlyRenderingFiber는 workInProgress의 또 다른 이름(workInProgressHook에서 구분하기 위해 다른 이름으로 변수 추가 생성) 타입은 null아니면 Fiber
renderWithHooks()에서 workInProgress를 할당
(renderWithHooks는 render phase에서 호출)
다시 말해, currentlyRenderingFiber가 fiber와 동일하다(null X)라는 의미는 renderWithHooks()가 호출되었다는 의미이다.

fiber와 alternate(current와 workInProgress)

fiber는 current와 workInProgress둘다를 가리킨다.
alternate는 fiber.alternate
여기에는 current와 workInProgress가 서로를 참조하는 주소값을 할당한다.
하지만, VDOM과 React lifeCycle에서 배운것과 같이 workInProgress(fiber)는 commit phase를 지나면서 current(fiber)로 바뀌고 current(fiber)를 참조복사해서 새로운 workInProgress(alternate)가 만들어진다.

render phase에서 setState

이미 idle에서 work를 scheduler에 등록했기 때문에 다시 WORK를 등록할 필요가 없고, 최적화할 필요도 없다.
render phase update가 더이상 발생하지 않을 때 까지 컴포넌트를 재호출하고 action(setState)을 소비하게 된다.

render phase에서 update의 저장

didScheduleRenderPhaseUpdate
기존에 진행 중이던 update를 잠깐 담아둘 임시 저장소가 필요하다. 그리고 renderPhaseUpdates(Map)은 객체와 비슷하게 key, value형태로 값을 저장한다.
이때 key의 type으로 string뿐만 아니라 객체도 가능하다.
linked list형태로 renderPhaseUpdates를 저장한다.

render phase에서 update의 소비

renderWithHooks()에서 renderPhaseUpdates에 저장한 update소비한다.
didSchduleRenderPhaseUpdate로 발생여부를 판단한다.
numberOfReRenders
hook업데이트 구현체에서 render phase update를 소비하기 위해 필요한 변수들의 값을 할당
nextCurrentHook
hook 업데이트를 구현테를 dispatcher에 주입한다.
ReactCurrentDispatcher.current = HooksDispatcherOnUpdate

update진행(소비)중에 다시 update발생

순서
component 재 호출 > 다시 update발생할 경우 didSchduleRenderPhaseUpdate값은 true > numberOfReRenders가 +1되고 25번까지 반복한다.

  • useState는 얼마나 많은 re-rendering을 진행할까?
    위에서 설명한 것과 같이 rendering을 최대 25번을 진행한다. 그럼 이후에는 어떤 결과가 생길까?
    우리가 한번 씩 코드를 잘못작성하거나 useEffect의 의존성 배열을 잘못넣을 경우 만나는 error가 있다.

To many re-renders, React limits the number of renders to prevent and infinite loop

이런 error를 만나는 경우 useState의 state값이 rendering을 25번 진행하였고, 너무 많은 rendering을 진행하기 때문에 발생하는 것으로 파악할 수 있다.

profile
성장에 미쳐버린 Frontend Developer

0개의 댓글