Reconciler

역할

  • Function또는 class컴포넌트의 render 함수를 실행해서 jsx를 vdom으로 변경
  • 새로운 vdom과 기존 vdom을 비교한다.
  • diff통해서 변화한 부분을 체크한다.
  • renderer를 통해서 DOM을 화면에 뿌려준다.

fiber관련 태그 설명.

  • type
    • FunctionComponent ⇒ 함수자체
    • ClassComponent ⇒ 클래스
    • HostComponent ⇒ tagName
  • tag
    • FunctionComponent
    • ClassComponent
    • HostComponent
  • effectTag
    • Placement
    • Update
    • PlacementAndUpdate
    • Deletion
    • Passive
  • effectList(firstEffect, nextEffect, lastEffect)
  • stateNode => DOM객체 저장.

과정

  • render
    • beginWork
    • completeWork
  • commit
    • before Mutation
    • mutation
    • layout

render단계

beginWork

  • (mount)fiber.tag에 따라 서로 다른 Fiber노드 생성.
  • (update) 만약 current가 최적화 될수 있다면 current를 그대로 사용(Diff)
  • fiber에 EffectTag생성

completeWork

  • (mount)fiber.stateNode에 관련된 DOM노드 생성
  • (mount)children DOM노드를 생성된 fiber.stateNode DOM노드에 insert
  • (mount) props 처리
  • (update) fiber.updateQueue처리
  • (update) props diff 처리후 fiber.pendingProps에 저장.
  • effectTag 생성된 fiber에 대해서 effectList에 추가.

commit

commit start

effectList중 Passive 태그가 존재할 경우 flushPassiveEffects(Immediate) 실행.


before mutation (commitBeforeMutationEffects)

  • DOM노드 랜더/삭제후 focus, blur 관련 로직처리.
  • getSnapshotBeforeUpdate(ClassComponent)
  • flashPassiveEffects (Normal)

mutation (commitMutationEffects)

  • effectTag에 따라 처리
    • Placement
    • Update
      • FunctionComponent
        • effectList에서 모든 useLayoutEffect의 destory 함수 실행.
      • HostComponent
        • fiber.updateQueue중 대응하는 내용 화면에 랜딩.
        • fiber.pendingProps내용 화면에 랜딩
    • Deletion

layout (commitLayoutEffects)

  • 라이프사이클 및 hook 실행
    • FunctionComponent
      • useLayoutEffect 콜백 함수 실행.(sync)
      • useEffect destor 함수와 콜백함수 초기화(async)
    • classComponent
      • componentDidMount, componentDidUpdate
      • this.setState의 콜백함수 실행.
    • HostRoot
      • render fn 콜백함수 실행.
  • DOM Instance에 따라 ref업데이트
  • current Fiber 트리 변환

layout After

  • fushPassiveEffects 실행(useEffect destor 및 useEffect callback)
  • flushSyncCallbackQueue 실행(예: useLayoutEffect 내부에 사용한 setState)

hostConfig 외부 API(react-dom 빌드시 해당 부분 함께 빌드)

import ReactReconciler from "react-reconciler";

const hostConfig = {
  now: Date.now,
  getRootHostContext: () => {},
  clearContainer: () => {},
  prepareForCommit: () => {},
  resetAfterCommit: () => {},
  getChildHostContext: () => {},
  shouldSetTextContent: () => {},
  createInstance: () => {},
  createTextInstance: () => {},
  appendInitialChild: () => {},
  appendChild: () => {},
  finalizeInitialChildren: () => {},
  supportsMutation: true,
  appendChildToContainer: () => {},
  prepareUpdate = () => {},
  commitUpdate = () => {},
  commitTextUpdate = () => {},
  removeChild = () => {},
}
const ReactReconcilerInst = ReactReconciler(hostConfig);

export const render = (reactElement, domElement, callback) => {

  if (!domElement._rootContainer) {
    console.log(ReactReconcilerInst);
    domElement._rootContainer = ReactReconcilerInst.createContainer(domElement);
  }
  // 컨테이너 업데이트
  return ReactReconcilerInst.updateContainer(reactElement, domElement._rootContainer, null, callback);
}

export default {
  render
}
// "react-reconciler": "0.26.2",
// "react": "17.0.2",

effectList => subtreeFlags

  • effectList인 경우

  • subtreeFlags

  • B의 effect는 Passive이고 bubble을 통해서 A로 이동, A.subtreeFlags에 Passive포함.
  • E의 effect는 Placement이고 bubble통해서 D로 이동, D.subtreeFlags에 Placement포함.
  • D.subtreeFlags에 Placement가 bubble통해서 C로 이동
  • C의 effect는 Update이고, C.subtreeFlags의 Placement가 bubble통해서 A로
  • A.subtreeFlags는 Passive、Placement、Update를 포함.
  • commit단계에서 모든 tree를 순회하면서 처리.

https://gist.github.com/jl917/059c3c47a521914cb8ed8fa2b5ff8569


참고