React Fiber

우아한테크코스 7기 피터

리액트를 사용하며
이런 궁금증 가져보신 적 있으신가요?

Q1) setState를 실행했는데 상태값이 바로 바뀌지 않지?

              
                function App(){
                  const [count,setCount] = useState(0);
                  
                  const handleClick = () => {
                    setCount(5); 
                    console.log(count); // 0

                    setCount(10); 
                    console.log(count); // 0
                  }
                }
              
            

리액트를 사용하며
이런 궁금증 가져보신 적 있으신가요?

Q2) 훅을 if문이나 함수 안에서 호출하면 안되지?

 
                
                  function App(){
                    if(condition){
                      const [state,setState] = useState(0); 
                      // [Error]
                      // React has detected a change in the order of Hooks called.
                      // This will lead to bugs and errors if not fixed.
                      // 리액트가 훅 순서의 변경을 감지했습니다.
                      // 이는 버그와 오류를 발생시킬 수 있습니다.
                    }
                  }
                
              

리액트를 사용하며
이런 궁금증 가져보신 적 있으신가요?

Q1) setState를 실행했는데 상태값이 바로 바뀌지 않지?

Q2) 훅을 if문이나 함수 안에서 호출하면 안되지?

=> React Fiber

이번 시간의 목표

  1. 앞선 궁금증에 대한 답을 찾아보자.

    Q1) setState를 실행하면 상태값이 바로 바뀌지 않지?

    Q2) 훅을 if문이나 함수 안에서 호출하면 안되지?

  2. '리액트 파이버란 ____이다.'에 대한 답을 내려보자.

목차

  1. React Fiber의 두 가지 역할
    1. Fiber 재조정자
    2. Fiber Node
  2. React Fiber의 주요 속성
    1. updateQueue
    2. memoizedState
    3. 그 외 속성
  3. 마무리

1. React Fiber의
두 가지 역할

1. React Fiber의
두 가지 역할

1) Fiber 재조정자

1) Fiber 재조정

재조정

: 렌더링 이전과 이후의 가상 돔을 비교하여
변경사항을 실제 돔에 적용하는 작업

렌더링 :
함수(함수형 컴포넌트)가 호출되어
가상돔이 만들어지는 과정

1) Fiber 재조정자

React16 이전 : 스택 재조정자

  • 렌더링 작업을 순차적으로 처리

단점

  1. 렌더링 블로킹

    : 처리 중이던 렌더링이 완료될 때까지
    다른 작업을 수행할 수 없는 상태

=> Fiber 재조정자

1) Fiber 재조정자

: React16에서 등장한 재조정 엔진

  • 각 렌더링 작업을 잘게 나누어
  • 우선순위가 더 높은 작업을 먼저 처리

1. React Fiber의
두 가지 역할

2) Fiber Node

2) Fiber Node

React16.8 이전 : 무상태 컴포넌트

  • 함수형 컴포넌트가 존재하기는 했지만
  • 상태를 가질 수 없었다.

=> React Hooks

=> Fiber Node가 관리

2) Fiber Node

: 훅을 포함한 컴포넌트의 모든 상태를
저장하는 자바스크립트 객체

2) Fiber Node

: 훅을 포함한 컴포넌트의 모든 상태를
저장하는 자바스크립트 객체

  • 이번 시간에 주로 다루게 될 내용

2. React Fiber의
주요 속성

1) 컴포넌트의 유형과 ID를 정의하는 속성들

                
                export type Fiber = {
                  tag: WorkTag;       // 컴포넌트 유형 (함수형, 클래스형, 호스트 등)
                  key: null | string; // React 엘리먼트의 고유 식별자 (주로 리스트에서 사용)
                  elementType: any;   // React.createElement 호출 시 사용된 원래 타입
                  type: any;          // 컴포넌트 정의 (함수형 컴포넌트의 함수, 
                                      // 클래스 컴포넌트의 클래스)

                  stateNode: any;     // 호스트 컴포넌트의 DOM 노드나 클래스 컴포넌트의 인스턴스
                  // ..
                };
                
              

2) Fiber 노드 간의 관계를 정의하는 속성들

                
                  export type Fiber = {
                    return: Fiber | null;  // 부모 Fiber (이 Fiber를 렌더링한 컴포넌트)
                    child: Fiber | null;   // 첫 번째 자식 Fiber
                    sibling: Fiber | null; // 다음 형제 Fiber
                    index: number;         // 같은 부모 내에서의 인덱스 (형제 간 순서)
                    // ..
                  };
                
              

3) React ref 관련 속성들

                
                  export type Fiber = {
                    ref: RefObject;                     // ref 객체 또는 함수
                    refCleanup: null | (() => void);    // ref 정리를 위한 콜백 함수
                    // ..
                  };
                
              

4) 컴포넌트의 데이터와 상태를 관리하는 속성들

                
                export type Fiber = {
                  pendingProps: any;       // 아직 처리되지 않은 새 props
                  memoizedProps: any;      // 마지막으로 렌더링된 props
                  updateQueue: mixed;      // 상태 업데이트, 콜백, 사이드 이펙트를 위한 큐
                  memoizedState: any;      // 함수형 컴포넌트의 훅 목록(연결 리스트)을 저장
                                          // 클래스 컴포넌트에서는 state 객체를 저장
                  dependencies: Dependencies | null; // 컨텍스트, 이벤트 등 외부 의존성
                  mode: TypeOfMode;       // Concurrent, Strict 등의 렌더링 모드
                  // ..
                };
              
            

5) 업데이트와 사이드 이펙트를 추적하는 속성들

                
              export type Fiber = {
                flags: Flags;            // 이 Fiber에 적용할 작업 종류
                                         // (배치, 업데이트, 삭제 등)
                subtreeFlags: Flags;     // 자식 Fiber들에 적용할 작업 종류
                deletions: Array | null; // 삭제될 자식 Fiber들의 배열
                // ..
              };
              
            

6) 우선순위와 스케줄링 정보를 담는 속성들

                
                  export type Fiber = {
                    lanes: Lanes;       // 이 Fiber의 작업 우선순위
                    childLanes: Lanes;  // 자식 Fiber들의 작업 우선순위
                    // ..
                  };
              
            

7) 진행 중인 작업과 커밋된 작업 사이의 관계

              
                export type Fiber = {
                  // ..
                  alternate: Fiber | null; // 현재 트리와 작업 중인 트리 사이의 대응 Fiber
                };
              
            

이번 시간에 주로 다루게 될 속성

              
                export type Fiber = {
                  // ..
                  updateQueue: mixed;      // 상태 업데이트, 콜백, 사이드 이펙트를 위한 큐
                  memoizedState: any;      // 함수형 컴포넌트의 훅 목록(연결 리스트)을 저장
                                           // 클래스 컴포넌트에서는 state 객체를 저장
                };
              
            

1) updateQueue

Q1) setState를 호출했는데 상태에 바로 반영이
바로 안되지?
                
                  const [count,setCount] = useCount(0);
                  
                  const handleClick = () => {
                    setCount(count+1); 
                    console.log(count); // 0
                    setCount(count+1); 
                    console.log(count); // 0
                  } 
                
              

1) updateQueue

: 상태 업데이트를 관리하는 큐

  • setState를 실행하면 updateQueue에 추가하고,
    렌더링 주기가 끝날 때 업데이트를 한 번에 처리

    • 렌더링 주기 : 이벤트 핸들러, 생명주기 메서드

1) updateQueue

Q1) setState를 호출했는데 상태에 바로 반영이
바로 안되지?
                
                  const [count,setCount] = useCount(0);
                  
                  const handleClick = () => {
                    setCount(count+1); 
                    console.log(count); // 0
                    setCount(count+1); 
                    console.log(count); // 0
                  } 
                
              

A) Fiber의 updateQueue에 상태 업데이트가 쌓이고
렌더링 주기가 끝날 때 일괄 처리되기 때문

=> 리액트의 Batch 업데이트

2) memoizedState

Q2) 훅을 if문이나 함수 안에서 호출하면 안되지?
                
                  if(condition){
                    const [state,setState] = useState(0); 
                    // [Error]
                    // React has detected a change in the order of Hooks called.
                    // This will lead to bugs and errors if not fixed.
                  }
                
              

2) memoizedState

              
                function ExampleComponent() {
                  const [count, setCount] = useState(0);         // 1번째 Hook
                  const [text, setText] = useState('hi');        // 2번째 Hook

                  useEffect(() => {                              // 3번째 Hook
                    document.title = text + count;
                  }, [text, count]);
                  // ..
                }
              
            
              
                Fiber.memoizedState = {
                  memoizedState: 0, // useState(0)
                  next: {
                    memoizedState: 'hi', // useState('hi')
                    next: {
                      memoizedState: { deps: ['hi', 0], ... }, // useEffect
                      next: null
                    }
                  }
                }
              
            

2) memoizedState

  • 리액트의 훅을 저장
  • => 함수형 컴포넌트가 리렌더링되어도 훅의 이전 상태를 기억

2) memoizedState

Q2) 훅을 if문이나 함수 안에서 호출하면 안되지?
                
                  if(condition){
                    const [state,setState] = useState(0); 
                    // [Error]
                    // React has detected a change in the order of Hooks called.
                    // This will lead to bugs and errors if not fixed.
                  }
                
              

A) 훅은 Fiber의 memoizedState에 연결 리스트 형태로
저장되어, 순서가 바뀌면 이전 상태와 매칭이
불가능해지기 때문

3) Fiber의 그 외 속성

  1. lanes : 작업 우선순위를 관리 => 동시성 모드
    • Transition API
    • Suspense
  2. alternate : 현재 트리와 작업 중인 트리
    사이의 연결을 관리
    • 재조정
    • 가상돔
  3. memoizedProps / pendingProps

    : 컴포넌트의 props를 관리

3. 마무리

그래 피터, React Fiber가 리액트의 내부 구조인 건 알겠어
근데 이게 내가 개발하는데 정말 도움이 될까?

  1. 리액트의 핵심 기술을 빠르고 쉽게 배우기 위해서
    • CS지식이 개발자에게 필요한 이유와 비슷한 맥락
    • 리액트의 핵심 기술 : 훅, 동시성과 Transitions, Suspense, React Server Component 등
  2. 면접 준비를 위해서
    • 프론트엔드 개발자 면접 질문
    • 가상돔, 컴포넌트 라이프 사이클, 재조정, 동시성

      이러한 질문에 대한 답변을 잘하기 위해서 리액트 파이버같은 내부 구조가 빠질 수 없다.

그래 피터, React Fiber가 리액트의 내부 구조인 건 알겠어
근데 이게 내가 개발하는데 정말 도움이 될까?

  • 개발을 하는데 필요한 실용적 지식을 학습하는 것이 우선
  • 이번 시간에는 '리액트 내부는 대략 이런 식으로 동작하는구나', '내가 알고 있던 것들이 파이버와 관련이 있었구나' 정도의 이해만으로도 충분

요약

"리액트 파이버란 리액트의 재조정 엔진이자
컴포넌트의 모든 상태를 관리하는
자바스크립트 객체이다."

감사합니다🙇‍♂️

참고자료