개발새발 로그

가상 DOM과 파이버노드를 Deep테일하게 알아보자! 본문

React

가상 DOM과 파이버노드를 Deep테일하게 알아보자!

이즈흐 2024. 4. 8. 04:08

리액트의 특징 중 가장 많이 언급되는 것이 가상 DOM이라는 것이다.

하지만 이 가상 DOM에 대해서 자세히 모르는 경우가 많다.

 

이번 포스팅에서는 가상 DOM에 대해서 자세히 알아보려고 한다.

 

가상 DOM 생긴 이유?

가상 DOM은 왜 생겼을까?

가상 DOM 이전에 DOM을 먼저 알아보자

 

DOM이란

웹페이지에 대한 인터페이스로 브라우저가 웹페이지의 콘텐츠와 구조를 어떻게 보여줄지에 대한 정보를 담고 있다.

 

그럼 브라우저가 웹 사이트에 접근요청을 받고 화면을 그리는 과정을 살펴보자

CRP(Critical Rendering Path)

브라우저는 위 과정을 거쳐서 웹페이지를 렌더링 한다.

 

그렇다면 사용자의 인터렉션으로 업데이트가 된다면 어떻게 될까?

위처럼 자바스크립트가 DOM을 수정해서 업데이트가 발생한다.

DOM이 수정되면 CRP가 다시 실행된다.

그러면 Layout Painting이 일어나게 된다. (Reflow와 Repaint)

 

결과적으로 더 많은 비용이 들게 된다.

 

가상 DOM의 등장

요즘에는 하나의 인터렉션으로 페이지 내부의 DOM의 여러 가지가 변경되는 시나리오가 대부분이다.

이러한 인터렉션에 따라 DOM의 모든 변경사항을 추적하는 것은 개발자 입장에서는 너무 수고스러운 일이다.

그리고 대부분의 개발자는 인터렉션에 모든 DOM 변경 경보다는 결과적으로 만들어지는 DOM 결과물 하나만 알고 싶을 것이다.

 

이런 문제를 해결하기 위해 가상 DOM이 탄생했다.

가상 DOM웹페이지가 표시해야 할 DOM을 일단 메모리에 저장하고, 리액트가 실제 변경에 대한 준비가 완료되었을 때 실제 브라우저의 DOM에 반영한다.

이렇게 DOM 계산을 브라우저가 아닌 메모리에서 계산하는 과정을 한 번 거치게 된다면 실제로는 여러 번 발생했을 렌더링 과정을 최소화할 수 있고, 브라우저와 개발자의 부담을 덜 수 있다.

 

여기서 궁금한 것은 가상 DOM이 어떻게 관리되냐는 것이다.

 

리액트의 렌더링 과정을 보자

 

이해하기 쉽도록 먼저 리액트의 렌더링 과정을 가져와보았다.

위 그림에서 우리가 알고 싶은 가상 DOM이 과정에 보인다.

 

컴포넌트렌더링 이후에 엘리멘트 렌더링 과정에서 가상 DOM이 나타나고, 재조정 과정을 거친다.

근데 이걸 렌더 페이즈와 커밋 페이즈로 나누고 있다.

 

우리가 자세히 볼 부분은 렌더 페이즈커밋 페이즈다.

 

그럼 먼저 렌더 페이즈의 컴포넌트 렌더링 과정을 살펴보자.

 

컴포넌트 렌더링 과정

렌더페이즈에 있는 컴포넌트 렌더링 과정을 간단하게 살펴보자.

 

위처럼 컴포넌트를 호출하면 객체가 생성된다.

컴포넌트를 호출했을 때 Babel로 컴파일된 결과를 보면 왜 객체로 변하는지 알 수 있다.

이미지에서 보이듯이 createElement라는 함수에 객체가 들어가 있는 모습이다.

이 결과물은 아래처럼 객체로 반환된다.

{type: A , props: {required: true}, children: "Hellow World"}

 

이 과정까지가 컴포넌트 렌더링 과정이다.

이를 통해 나오는 객체가 React Element다.

 

그렇다면 반환된 React Element가 어떻게 실제 DOM으로 반영되는 것일까?

먼저 알아야 할 점은 react Element 내용이 실제 DOM에 반영되기 위해서는 먼저 가상 DOM에 추가되어야 한다.(Update Fiber)

즉 react Element 만으로는 가상 DOM에 추가하기가 어렵고, 몇 가지 정보가 4추가되어야 한다.

몇 가지 정보가 바로 Fiber다.

Fiber는 컴포넌트의 상태, life cycle, hook 관리된다. (Fiber도 자바스크립트 객체이다.)

결과적으로 react Element확장한 것Fiber이다.

 

Fiber가 무엇일까?

먼저 헷갈려서는 안 되는 것이 있다.

Fiber 아키텍처와 Fiber는 다른 것이다. 

이름이 동일하지만 다른 것으로 알아야 한다.

현재 여기서 말하는 Fiber는 가상 DOM의 노드 객체라고 이해하면 된다.

 

가상 DOM은 Fiber 노드 객체로 이루어져 있다.

그럼 어떻게 React Element를 Fiber노드로 확장하는 것일까?

다시 React Element를 생성하는 과정을 자세하게 알아보자.

 

다시 한번 컴포넌트를 호출해 보자

const CustomComponent = () => '';
const App = () => <><CustomComponent /><div id="host_component"></div></>

위 코드를 Babel로 트랜스파일하면 아래와 같다.

const App = () => (
  React.createElement(
    React.Fragment, // type: Symbol.for('react.fragment')
    {}, // config
    React.createElement( // 첫번째 자식
      CustomComponent, // type: function
      {}, // config
      // 자식은 없음
    ),
    React.createElement( // 두번째 자식
      "div", // type: tag name
      { id: "host_component" } // config
      // 자식은 없음
    ) 
  );

createElement를 통해서 ReactElement를 만든다고 했다.

createElement는 아래와 같은 과정으로 이루어져 있다.

const RESERVED_PROPS = {
  key: true,
  ref: true,
};

function createElement(type, config, children) { 
  // 1
  let propName;

  const props = {};

  let key = null;
  let ref = null;

  if (config != null) {
    if (hasValidRef(config)) { // config.ref !== undefined;
      ref = config.ref;
    }
    if (hasValidKey(config)) { // config.key !== undefined;
      key = '' + config.key;
    }

    // 예약된 속성을 제외한 나머지를 props 객체에 저장
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  // 2
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  // 3
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }

  // 4
  return ReactElement(
    type,
    key,
    ref,
    props,
    /*...*/
  );
}

위 과정을 간단히 요약하면 아래와 같다.

  1. React element에는 key와 ref라는 예약된 속성들이 존재합니다. config에 예약 속성을 제외한 나머지를 props 객체에 저장합니다.
  2. 복수의 자식이 넘어온다면 하나의 배열에 저장합니다.
  3. default props가 존재할 경우 props 객체에 적용합니다.
  4. 1 ~ 3에서 작성한 정보를 가지고 React element 객체를 만듭니다.

그러면 아래와 같은 ReactElement가 반환이 된다.

const ReactElement = function(type, key, ref, props,...) {
  const element = {
    // This tag allows us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,
    // Built-in properties that belong on the element
    type: type,
    key: key,
    ref: ref,
    props: props,
  };
  return element;
};

특이하게 생긴 $$typeof가 있다.

이 속성은 fiber를 만들 때 element의 종류를 확인하는 데 쓰입니다.

기본적으로는 REACT_ELEMENT_TYPE이지만 스태틱 컴포넌트의 경우 심벌을 사용합니다.

 

스태틱 컴포넌트 중 간단하게 memo lazy만 확인해 보자.

  
import {REACT_MEMO_TYPE} from 'shared/ReactSymbols';

function memo<Props>(
  type: React$ElementType,
  compare?: (oldProps: Props, newProps: Props) => boolean,
) {
  return {
    $$typeof: REACT_MEMO_TYPE,
    type,
    compare: compare === undefined ? null : compare,
  };
}
  
import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';

function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> {
  let lazyType = {
    $$typeof: REACT_LAZY_TYPE,
    _ctor: ctor,
    // React uses these fields to store the result.
    _status: -1,
    _result: null,
  };

  return lazyType;
}

리액트 코어 패키지가 하는 일은 대게 이런 리액트용 element를 만드는 거라고 생각하시면 된다.

Text는 React element로 변환하지 않습니다.

 

 

이제 Fiber로 확장하는 과정을 알아보자

React element의 종류를 type 심벌을 통해 판단했다면 fiber는 tag를 통해 판단한다.

이 tag의 명칭은 Work tag로 각 fiber 종류에 따라 재조정 작업의 처리가 달라야 하기 때문에 붙은 명칭입니다.

 

createFiber()

몇몇 종류의 fiber들은 props를 조금 다른 의미로 다루고 있다.

그래서 fiber 생성을 위한 사전 준비가 살짝 일반 fiber와는 다르다.

이 부분을 처리하기 위해 createFiberFrom***()의 형식으로 함수가 파생되어 있기는 하지만 결국 fiber를 만드는 최종 함수로 createFiber()를 사용하므로 해당 함수만 확인해 보자.

  const createFiber = function(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
): Fiber {
  return new FiberNode(tag, pendingProps, key, mode);
};

props를 특별하게 다루는 fiber는 FragmentText다.

해당 메서드들도 자세히 다루면 좋지만 포스팅 내용에서 벗어나므로 해당 링크로 확인해 보고,

우리는 일반적인 fiber를 생성하는 createFiberFromElement()를 확인해 보자.

createFiberFromElement()

해당 함수를 통해서 React Element를 Fiber로 확장시킨다.

이 함수가 어떤 과정을 거치는지 알아보자.

export function createFiberFromElement(
  element: ReactElement,
  mode: TypeOfMode,
  expirationTime: ExpirationTime,
): Fiber {
  const type = element.type;
  const key = element.key;
  const pendingProps = element.props;
  const fiber = createFiberFromTypeAndProps(
    type,
    key,
    pendingProps,
    mode,
    expirationTime,
  );
  return fiber;
}
  • 먼저 element에서 필요한 정보들을 꺼낸다.
  •  createFiberFromTypeAndProps()는 이 정보들을 이용하여 element의 type에 맞는 fiber로 확장한다.

createFiberFromTypeAndProps()

createFiberFromTypeAndProps()가 가장 먼저 해야 할 일은 여러 형태의 React element를 잘 분간하여 거기에 맞는 fiber tag를 찾아내는 것이다.

import {
  IndeterminateComponent,
  ClassComponent,
  MemoComponent,
  /*...*/
} from 'shared/ReactWorkTags'; // fiber tag
import {
  REACT_FRAGMENT_TYPE,
  REACT_MEMO_TYPE,
  /*...*/
} from 'shared/ReactSymbols'; // 스태틱 컴포넌트

export function createFiberFromTypeAndProps(
  type: any,
  key: null | string,
  pendingProps: any,
  mode: TypeOfMode,
  expirationTime: ExpirationTime,
): Fiber {
  let fiber;
  let fiberTag = IndeterminateComponent; 
  let resolvedType = type;

  if (typeof type === 'function') {
    // class component
    if (shouldConstruct(type)) { // type.prototype && type.prototype.isReactComponent;
      fiberTag = ClassComponent;
    }
//else?? 여기서는 함수형 컴포넌트라고 단정지을 수 없습니다.
    
  // type이 string이면 호스트 컴포넌트 입니다. ex) 'div', 'input'..
  } else if (typeof type === 'string') {
    fiberTag = HostComponent;

  // 이하 스태틱 컴포넌트
  } else {
    getTag: switch (type) {
      case REACT_FRAGMENT_TYPE:
        return createFiberFromFragment(
          pendingProps.children,
          mode,
          expirationTime,
          key,
        );
      case REACT_CONCURRENT_MODE_TYPE:
        fiberTag = Mode;
        mode |= ConcurrentMode | BlockingMode | StrictMode;
        break;
      /*...*/
      default: {
        if (typeof type === 'object' && type !== null) {
          switch (type.$$typeof) {
            case REACT_MEMO_TYPE:
              fiberTag = MemoComponent;
              break getTag;
            case REACT_LAZY_TYPE:
              fiberTag = LazyComponent;
              resolvedType = null;
              break getTag;
            /*...*/
          }
        }
        let info = '';
        invariant(
          false,
          'Element type is invalid: expected a string (for built-in ' +
            'components) or a class/function (for composite components) ' +
            'but got: %s.%s',
          type == null ? type : typeof type,
          info,
        );
      }
    }
  }

  fiber = createFiber(fiberTag, pendingProps, key, mode);
  fiber.elementType = type;
  fiber.type = resolvedType;
  fiber.expirationTime = expirationTime;

  return fiber;
}

 

위 코드도 중요한 부분이 몇 가지 있지만 해당 포스팅에서 적기에는 내용이 벗어나므로 해당 링크로 자세히 살펴볼 수 있다.

 

결과적으로 아래 코드를 실행해서 fiber가 반환되는 것이다.

  fiber = createFiber(fiberTag, pendingProps, key, mode);

아까 위에서 createFiber를 실행하면 new FiberNode를 실행했었다.
new FiberNode는 아래와 같다.

function FiberNode(tag, pendingProps, key){
  // Instance
  this.tag = tag; // fiber의 종류를 나타냄
  this.key = key;
  this.type = null; // 추후에 React element의 type을 저장
  this.stateNode = null; // 호스트 컴포넌트에 대응되는 HTML element를 저장

  // Fiber
  this.return = null; // 부모 fiber
  this.child = null; // 자식 fiber
  this.sibling = null; // 형제 fiber
  this.index = 0; // 형제들 사이에서의 자신의 위치

  this.pendingProps = pendingProps; // workInProgress는 아직 작업이 끝난 상태가 아니므로 props를 pending으로 관리
  this.memoizedProps = null; // Render phase가 끝나면 pendingProps는 memoizedProps로 관리
  this.updateQueue = null; // 컴포넌트 종류에 따라 element의 변경점 또는 라이프사이클을 저장
  this.memoizedState = null; // 함수형 컴포넌트는 훅을 통해 상태를 관리하므로 hook 리스트가 저장된다.

  // Effects
  this.effectTag = NoEffect; // fiber가 가지고 있는 side effect를 기록
  this.nextEffect = null; // side effect list 
  this.firstEffect = null; // side effect list
  this.lastEffect = null; // side effect list 

  this.expirationTime = NoWork; // 컴포넌트 업데이트 발생 시간을 기록
  this.childExpirationTime = NoWork; // 서브 트리에서 업데이트가 발생할 경우 기록

  this.alternate = null; // 반대편 fiber를 참조
}

 

코드를 살펴보면서 React Element가 어떻게 Fiber Node로 확장되는지 알아보았다.

 

이제 Fiber Node로 확장했어 가상 DOM에서 어떻게 활용되는지 알아보자

 

 

가상 DOM과 Fiber Node

가상 DOM은 프로그래밍 콘셉트이다.

메모리 상에 UI 관련 정보를 띄우고 react-dom과 같은 라이브러리에 의해 실제 DOM과 sync를 맞춘다.

이를 재조정이라 부른다.

 

가상 DOM을 쓰는 이유는 실제로 DOM을 조작하고 조작한 DOM을 브라우저가 화면에 보여줘야 하는 과정이 가상에서 하는 것보다 훨씬 더 비용이 들게 된다.(오래 걸림)

 

그럼 가상 DOM은 어떻게 구성되어 있지?

그림에서 보이는 트리구조는 어디서 많이 봤을 것이다.

바로 DOM 트리구조이다.

근데 여기서 다른 점은 DOM 트리 노드들이 Fiber 노드로 교체된 것이다.

가상 DOMFiber 노드들로 구성된 트리 형태다.

 

여기서 자세히 보면 currentworkInProgress 두 가지 트리가 구성되어 있다.

이 두 가지 트리는 더블 버퍼링 구조를 뜻한다.

 

current와 workInProgress를 간단하게 설명하면

current

  • 실제 DOM에 mount 된 Fiber

현재 current에서 연결된 Root Node와 그 위의 ReactDOM.render를 보면 알 수 있는 것이 있다.

즉 current는 실제 HTML에 적용되어있는 정보이다.

workInProgress

  • 렌더 페이즈에서 작업 중인 Fiber
  • 커밋 페이즈를 지나면서 current tree가 됨

workInProgress Tree는 current Tree에서 자기 복제하여 만들어진다.

그리고 그림에서 보이듯이 alternate로 서로 참조하고 있다.

 

alternat로 서로 참조하고 있다는 것의 의미가 무엇일까?

Fiber 노드들은 모두 객체이다.

그 객체안에 alternate라는 key를 가지고 있고,

keyvalue 값으로 객체 Reference(서로 참조하고 있음)가 담겨있다는 것이다.

 

 workInProgress는 추가,수정,삭제 등의 작업을 하고 있다.

이 작업이 끝나고 커밋 페이즈를 지나가면 workInProgress는 current가 된다. (아마도 이때 더블버퍼링을 수행한다고 하는 것 같다.)

Root Node에 참조로 current와 연결되어 있던 것이 끊어지고 workInProgress로 연결이 된다.

그리고 workInProgress에서 자기복제하여 새로운 newWorkInProgress가 만들어진다.

 

 

그럼 결과적으로 current와 workInProgress를 비교(diffing)하고 재조정하는 것인가?

가상 DOM 내에서 current 트리와 workInProgress 트리를 비교(diffing)하여 재조정(reconciliation) 과정을 수행한다고 한다.

아래 내용을 보자.

1. Diffing

Diffing은 현재의 가상 DOM(current 트리)과 변경 후의 가상 DOM(workInProgress 트리)를 비교하는 과정입니다. 이 과정에서 리액트는 다음과 같은 규칙을 따릅니다:

  • 타입의 비교: 두 트리에서 같은 위치에 있는 엘리먼트의 타입을 비교합니다. 만약 엘리먼트의 타입이 다르다면, 리액트는 이전 엘리먼트를 버리고 새 엘리먼트로 교체합니다. 이는 하위 컴포넌트도 모두 새로 생성된다는 것을 의미합니다.
  • 키의 비교: 자식 엘리먼트들을 비교할 때, 리액트는 key 속성을 사용하여 재배열을 파악합니다. 같은 key를 가진 엘리먼트는 동일한 엘리먼트로 간주되어, 이동된 위치로 재배치됩니다.
  • 속성의 비교: 같은 타입의 두 엘리먼트에서 속성이 변경되었는지 비교합니다. 속성이 변경되었다면, 변경된 속성만을 실제 DOM에 반영합니다.

2. 재조정 (Reconciliation)

Diffing 과정을 통해 식별된 변경 사항을 바탕으로, 리액트는 실제 DOM을 업데이트하는 과정입니다. 재조정 과정에서 리액트는 다음 단계를 따릅니다:

  • 업데이트 단계: 변경된 속성이나 상태를 가진 컴포넌트의 render 함수를 호출하여 새로운 가상 DOM을 생성합니다. 이때 shouldComponentUpdate와 같은 라이프사이클 메소드를 통해 불필요한 업데이트를 걸러낼 수 있습니다.
  • 커밋 단계: 실제 DOM에 변경사항을 반영합니다. 이 단계에서 리액트는 componentDidMount나 componentDidUpdate와 같은 라이프사이클 메소드를 호출합니다.

 

여기까지 알아보면서 가상 DOM에 대해서 조금 확실하게 배웠다고 느꼈다.

그러면 이러한 가상 DOM을 재조정하고 반영하는 렌더 페이즈와 커밋페이즈 즉 Life Cycle을 다시한번 되짚어보자

 

React Life Cycle - 렌더 페이즈와 커밋 페이즈

Render phase

Render phase는 쉽게 말해 가상 DOM 조작 단계라고 생각하면 된다. (VDOM 재조정 단계)
리액트는 변경점이 생겼을 때(element의 추가, 수정, 삭제) 이를 가상 DOM에 반영하기 위해 Work를 담당하는 함수를 scheduler를 통해 실행시킨다.

Work : reconciler 가 컴포넌트의 변경을 DOM에 적용하기 위해 수행하는 일
Scheduler : react는 Task를 비동기로 실행함, 이 Task를 실행하는 타이밍을 알고 있는 패키지

 

결국 reconcilerscheduler라는 또 다른 패키지에 Work를 등록한다.

등록한 Work들 scheduler가 타이밍에 맞게 실행하는 역할을 한다.

전체적인 과정은 reconciler가 담당한다.

 

reconciler : fiber 아키텍쳐에서 VDOM 재조정 담당, 컴포넌트를 호출하는 곳 

 

근데 이때 reconciler는 큰 변화가 있었다.

React 16버전 이전에는 reconciler의 아키텍쳐는 스택 알고리즘으로 이루어져있었다.

스택이라는 이름에서 알 수 있듯이 스택에 렌더링에 필요한 작업들이 쌓이면

스택이 빌 때까지 동기적으로 작업이 이루어졌다.

 

자바스크립트의 특징인 싱글 스레드라는 점으로 인해 이 동기 작업은 중단될 수 없고, 다른 자업이 수행되고 싶어도 중단할 수 없었으며, 이는 리액트의 비효율성으로 이어졌다.

 

그래서 등장한 것이 리액트 파이버 아키텍쳐다.

reconciler가 파이버 아키텍쳐로 바뀌면서 렌더링의 순서를 변경할 수 있게 되었다. (abort, stop, restart)

Fiber의 목표
1. 작업을 작은 단위로 분할하고 쪼갠 다음, 우선순위를 매긴다.
2. 이러한 작업을 중지하고 나중에 다시 시작할 수 있다.
3. 이전에 했던 작업을 다시 재사용하거나 필요하지 않은 경우에는 폐기할 수 있다.

여기서 중요한 것은 이 과정들이 모두 비동기로 이루어진다는 것이다.

리액트는 파이버라는 작업 단위를 하나씩 처리하고 finishedWork()라는 작업으로 마무리한다.
그리고 이 작업을 커밋해 실제 브라우저 DOM에 가시적인 변경 사항을 만들어낸다.
이를 아래 두 단계로 요약할 수 있다.

1. 렌더 단계에서 리액트는 사용자에게 노출되지 않는 모든 비동기 작업을 수행한다.
그리고 이 단계에서 언급한 파이버의 작업, 우선순위를 지정하거나 중지시키거나 버리는 등의 작업이 일어난다.
2. 커밋 단계에서는 앞서 언급한 것처럼 DOM에 실제 변경사항을 반영하기 위한 작업, commitWork()가 실행되는데 이 과정은 앞선 과정과 다르게 동기식으로 일어나고 중단될 수도 없다.

 

그럼 파이버 아키텍쳐가 적용되기 전에는 가상 DOM은 무슨 노드로 구성되어있던 거지?
- 찾아본 결과 가상 DOM의 노드는 일반적인 "가상 DOM 노드" 또는 "노드"로 불렸다.
- 그리고 가상 DOM 노드들은 리액트 엘리먼트컴포넌트 인스턴스로 구성되어있었다고 한다.
- 이때 재조정과정이 동기적으로 수행되어 반응성에 영향을 주었던 것이다.

Commit phase

Commit phase는 Render phase에서 재조정된 VDOM을 DOM에 적용하고 라이프 사이클을 실행하는 단계다.

여기서도 마찬가지로 DOM에 마운트된다는 것이지 페인트 된다는 건 아니다.

 

이 단계는 모드와는 상관없이 항상 일관적인 화면 업데이트를 위해 동기적으로 실행된다.

동기적으로 실행된다는 건 콜 스택을 한 번도 비우지 않고 DOM 조작을 일괄처리한다는 뜻이다.

그러므로 Commit phase 중간에 페인트 되지 않는다.

이 단계가 끝나고 리액트에서 콜 스택을 비워줘야지만 브라우저에서 화면을 페인트 할 수 있게 된다.

 

📖마무리하면서..

이렇게 가상 DOM을 자세히 알아보면서 가상 DOM과 연관된 내용들을 공부해보았다.

 

공부한 내용 중 특히 렌더 페이즈가 중요하다고 한다.

리액트의 useState훅을 호출해 setState가 state를 바꾸는 과정이 있는데

그 바꾸는 과정이 재조정(reconcileiation)이다.

즉 reconciler가 담당하는 것이다. 이러한 과정이 발생하는 페이즈가 렌더페이즈이다.

 

그래서 React Hook에 대해서 알기 위해서는 위와 같은 사전 지식이 필요하다.

이후 useState에 관련해서도 공부하고, 포스팅할 예정이다.

 

728x90
반응형
LIST