본문 바로가기

프로그래밍/frontend.

리액트 따라만들기 3. 성능 향상 및 fibers

이 글은 이 아티클을 따라 실습을 진행하며 작성한 글입니다.

이 전편의 내용은 링크를 통해 확인 해주세요!

 

 전편에서는 리액트의 렌더 함수를 직접 구현하여 리액트를 사용하지 않고, 컴포넌트를 렌더링 하는 것 까지 구현을 했습니다. 

 

 전편에서 만든 yuact는 렌더링 재귀적으로 진행 하고 있는데, 커다란 돔을 한번에 렌더링 하게 될 경우 메인스레드를 너무 오래 차지하기 때문에, 이를 조금 수정해야 합니다.

 

따라서, 작업을 작은 단위로 나누고 각 작업이 끝난 후, 다른 할 일이 있다면 렌더링을 중단해야 합니다. 

 

브라우저의 requestIdleCallback을 사용하면 브라우저가 유휴 상태 일때 콜백을 실행 할 수 있다.

let nextUnitOfWork = null;

function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }
  requestIdleCallback(workLoop);
}

requestIdleCallback(workLoop);

function performUnitOfWork(nextUnitOfWork) {
  // TODO
}

 

fiber 장에서는 렌더 트리를 fiber 구조로 만들기 위해 performUnit of work함수의 로직을 작성한다.

 

PerformUnitOfWork

function performUnitOfWork(fiber) {
  // TODO add dom node

  if (!fiber.dom) {
    fiber.dom = createDom(fiber);
  }

  if (fiber.parent) {
    fiber.parent.dom.appendChild(fiber.dom);
  }

  // TODO create new fibers
  const elements = fiber.props.children;
  let index = 0;
  let prevSibling = null;

  while (index < elements.length) {
    const element = elements[index];

    const newFiber = {
      type: element.type,
      props: element.props,
      parent: fiber,
      dom: null,
    };

    // TODO return next unit of work
    if (index === 0) {
      fiber.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }

    prevSibling = newFiber;
    index++;
  }
  if (fiber.child) {
    return fiber.child;
  }
  let nextFiber = fiber;
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling;
    }
    nextFiber = nextFiber.parent;
  }
}

 

--- 만들다 보니까 뭔가 리액트 앱 만들 때, jsx의 트리 구조를 어떤식으로 짜야할 지 감이 잡히는 것 같기도 하고,,---