리액트의 조화(Reconciliation) 과정 정리

신호승·2021년 1월 15일
13
post-thumbnail

이 글은 Max Koretskyi 가 리버스 엔지니어링으로 React의 Source Code를 보고, 렌더링 과정을 분석해 놓은 블로그를 참고하여 작성되었습니다. 원본 내용을 더 간소화시키고 제가 정리한 내용을 추가하여서 틀린 부분이 있을 수 있으므로, 피드백 환영합니다

이해를 돕기 위한 배경 지식

  • 이 글은 v16.0 버전 이후의 내용들을 다룸
  • 사용자가 만든 리액트 컴포넌트는 리액트 조화 과정 내에서 fiber에 대응됨 (component => react element => fiber)
  • 리액트는 브라우저 런타임에서 이 fiber 들을 활용하여 virtual DOM을 만듬

리액트 조화 과정 세부 구성요소

Render Phase

  • 변화된 사항을 감지하여 새로운 virtual DOM을 생성하는 과정
  • 변경사항들이 반영된 alternate virtual DOM tree를 생성하며, diffing algorithm을 이용하여 변화된 사항을 빠르게 적용하기 위한 effects list를 생성함

Commit Phase

  • Render phase에서 생성된 alternate tree와 effects list 를 활용하여 real DOM에 반영하는 과정

effects list

  • Render phase에서 생성된 real DOM 변경사항들을 가지고 있는 list

렌더 과정 정리 GIF


Step by Step 조화 과정

초기 상태

  • 처음 virtual DOM tree가 다음과 같이 구성되었다고 가정

외부 변화 사항이 일어남

  • 앱 사용자의 입력에 의해 B component의 state의 변경 혹은 props의 변화가 일어남

변화 사항이 일어난 fiber에 대해 flag(dirty check) 진행

  • B component에 대응되는 B Fiber에 dirty check 수행

Render phase 시작

  • renderRoot 함수가 실행되어 root로부터 렌더가 필요한 Fiber인 B를 빠르게 탐색함

Render phase 진행

  • 렌더가 필요한 Fiber부터 순차적으로 beginWork() 함수가 실행되며, 새로운 virtual DOM Fiber를 만드는 작업을 완료하면서 completeWork()을 호출함
  • 처음 dirty가 생긴 B Fiber의 completeWork() 호출이 끝나면 commit phase로 넘어감
  • 또한 Render phase에서 diffing algorithm을 이용하여 effect list를 만듬

Render phase - memoized component의 경우

  • 메모된 경우, 사용자가 입력한 compare function을 바탕으로 비교하거나 자체적인 shallow compare를 수행하여 새로 Component를 부를지 말지를 판단함
  • 비교 결과 True이면, 기존에 만들어놨던 Fiber를 다시 이용함
    updateMemoComponent
    updateSimpleMemoComponent
    bailoutOnAlreadyFinishedWork
  • 비교 결과 False이면, 새로 Component Function이나 Class를 호출하여 Fiber를 다시 만듬

Commit phase 시작

  • effect list에 있는 변경 사항들을 real DOM에 반영함

Commit phase - 변경사항이 없는 fiber의 경우

  • E Fiber의 경우, effect list에 추가되지 않음
  • 다만, 변경 사항이 없다고 하더라도 current와 alternate에 있는 fiber는 다른 객체임

Commit phase - memoized component의 경우

  • G Fiber는 current와 alternate가 같은 pointer를 공유하므로, 실제로는 같은 객체임

Commit phase 진행

렌더 완료

  • 변경사항 반영이 끝나고 새로운 vitual DOM Tree를 current tree로 가지고 있음

추가 참고 사항

Fiber는 엄밀히 말하면 트리 구조가 아닌 linked list로 연결되어 있다

  • Fiber node들은 child 및 sibling 포인터를 가지며, 이로 인해 linked list 형태로 연결되어 있음

Fiber는 비동기적인 call stack frame을 자체적으로 구현한 것이다

  • 리액트는 virtual DOM tree traversal을 수행할 때 DFS 방식의 recursion 순서로 진행한다고 보여짐
  • 다만, 브라우저의 built-in call stack을 그대로 이용하여 구현하면, 변경해야 할 node들이 너무 많을 경우에 멈추지 못하고 call stack이 빌 때까지 작업을 계속하게 되어 다른 작업이 지연될 수 있음
  • 따라서, 리액트 팀은 call stack을 중간에 interrupt하여 순서를 조작할 수 있는 비동기적인 가상의 stack frame model을 만들었으며, 그것이 Fiber 임

    원문 : If you rely only on the [built-in] call stack, it will keep doing work until the stack is empty…Wouldn’t it be great if we could interrupt the call stack at will and manipulate stack frames manually? That’s the purpose of React Fiber. Fiber is re-implementation of the stack, specialized for React components. You can think of a single fiber as a virtual stack frame.

Reference

Inside Fiber: in-depth overview of the new reconciliation algorithm in React
The how and why on React’s usage of linked list in Fiber to walk the component’s tree
The useEffect hook: a brief clarification on its usage

profile
Front-End developer

2개의 댓글

comment-user-thumbnail
2022년 8월 7일

React Fiber가 대체 뭔지, Reconciliation은 도대체 정확히 뭔지 궁금해서 한참을 헤맸는데요. 이 글을 보니까 이해가 매우 쉽고, 참고하셨다는 저 'Inside Fiber...' 포스트를 읽으니 정리까지 깔끔하게 되네요. 다들 '그래서 fiber가 뭔데..?'에 대한 대답을 제대로 주지 못했는데 속이 뚫리는 기분이네요. 감사합니다!

1개의 답글