ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React Activity?
    프론트엔드 2026. 3. 12. 18:47

    React 렌더링

    Activity 컴포넌트를 이해하기 전에 먼저 React에서 상태 업데이트가 어떻게 이루어지고 왜 리렌더링이 발생하는지 이해할 필요가 있다.

    React 공식 문서에서는 Activity가 hidden 상태일 때 렌더링을 수행하지 않는다고 설명하고 있기 때문에, 이를 이해하기 위해 먼저 React의 기본 렌더링 과정을 살펴보았다.

    예를 들어 다음과 같은 코드가 있다고 하자.

    function App() {
    const [count, setCount] = useState(0);
    
    return (
    <button onClick={() => setCount(count + 1)}>
    클릭
    </button>
    );
    }

    버튼을 클릭하면 setCount가 호출되고 React는 다음과 같은 과정을 통해 UI를 업데이트한다.

    setState
    ↓
    updateQueue에 update 추가
    ↓
    render phase 시작
    ↓
    컴포넌트 함수 실행
    ↓
    새로운 UI 계산
    ↓
    Reconciliation (이전 UI와 비교)
    ↓
    commit phase
    ↓
    DOM 업데이트
     

    Reconciler와 Reconciliation

    위 과정에서 중요한 부분은 Reconciliation(재조정) 단계이다.

    React는 이전 UI와 새로운 UI를 비교하여 어떤 부분이 변경되었는지 판단하고 필요한 부분만 DOM을 업데이트한다.

    이 작업을 수행하는 것이 Reconciler이며, 이 과정에서 React는 Fiber Tree라는 자료구조를 사용한다.


    Fiber Tree

    Fiber Tree는 React가 컴포넌트 구조를 관리하기 위해 사용하는 내부 트리 구조이다.

    각 컴포넌트는 하나의 Fiber Node로 표현되며, 다음과 같은 정보가 저장된다.

    type → 컴포넌트 타입
    props → 전달된 props
    memoizedState → 현재 state
    child → 첫 번째 자식 노드
    sibling → 형제 노드
    return → 부모 노드
     

    예를 들어 다음과 같은 컴포넌트 구조가 있을 때

    <App>
    <Header />
    <Content />
    </App>

    React 내부에서는 다음과 같은 Fiber Tree가 만들어진다.

    Fiber(App)
    ├ Fiber(Header)
    └ Fiber(Content)

    상태 업데이트가 발생하면

    setState가 호출되면 React는 바로 state를 변경하지 않고 먼저 updateQueue에 상태 변경 요청을 저장한다.

    예를 들어 다음과 같은 상태가 있다고 하자.

    function App() {
    const [count, setCount] = useState(0)
    const [name, setName] = useState("A")
    }

    React 내부에서는 Hook 상태가 다음과 같이 관리된다.

    Fiber(App)
    memoizedState

    Hook1
    state = 0
    next →
    Hook2
    state = "A"
     

    이때 count를 증가시키는 함수가 호출되면

    setState 호출

    updateQueue에 update 추가

    render phase에서 updateQueue 처리

    새로운 state 계산

    memoizedState 업데이트
     

    이 과정에서 React는 새로운 Fiber Tree(workInProgress)를 생성한다.


    Fiber Tree 비교

    React는 상태 업데이트가 발생하면

    current Fiber Tree
    VS
    workInProgress Fiber Tree
     

    를 비교한다.

    이 비교 과정이 바로 Reconciliation이며, 이를 수행하는 것이 Reconciler이다.

    구조는 다음과 같다.

    React
    └ Fiber Tree
    └ Fiber Node
    ├ memoizedState
    ├ updateQueue
    └ hooks

    왜 Fiber Tree를 두 개 유지할까?

    React 내부에는 두 개의 Fiber Tree가 존재한다.

    current Fiber tree
    workInProgress Fiber tree
     
    • current → 현재 화면에 렌더링된 UI 상태
    • workInProgress → 다음 UI 상태를 계산하는 트리

    렌더링 과정은 다음과 같이 진행된다.

     
    render phase
    current ───────────► workInProgress
    ▲ │
    │ │
    └────── commit ────────┘

    React는 workInProgress tree에서 새로운 UI를 계산한 뒤 commit 단계에서 current tree와 교체한다.

    이 구조 덕분에

    • 렌더링 도중 오류가 발생해도 기존 UI는 유지되고
    • 계산이 완료된 결과만 DOM에 반영되기 때문에

    UI 업데이트가 안정적으로 이루어질 수 있다.

     

    React Activity

    - React Activity는 새롭게 추가된 컴포넌트로 컴포넌트를 "숨김 상태로 유지하면서" 상태를 보존한다고 한다. 

    - 보통 React에서 버튼을 클릭하면 state 상태가 변경이 되어, 리렌더링이 발생한다. 

    - 하지만 Activity의 경우는 unmount 되지 않아 리렌더링이 발생하지 않는다 

    <Activity mode="hidden">
      <ChatPanel />
    </Activity>

     

    Activity가 어떻게 리렌더링이 일어나지 않도록 할까

    - Activity가 리렌더링을 하지 않는 이유를 간단히 말하면 일종의 스킵을 통해 리렌더링을 하지 않는다. 

    - 보통의 상태 업데이트가 일어난다면 아래와 같이 일어나지만, React Activity는 다르다. 

    setState
    ↓
    updateQueue에 update 추가
    ↓
    render phase 시작
    ↓
    컴포넌트 함수 실행
    ↓
    새 Fiber 생성
    ↓
    Reconciliation
    ↓
    commit phase
    ↓
    DOM 업데이트

    - React는 memoizedState를 통해 visible한 상태인지 hidden 상태인지를 관리한다고 한다. 

    - 다시 React 동작원리를 보면 리액트에서 렌더링은 아래와 같이 렌더단계에서 내부에서는 Fiber를 하나씩 순회하며 렌더링 작업을 수행한다고 한다. 

    - React는 memoizedState를 통해 Offscreen Fiber가 visible 상태인지 hidden 상태인지 관리한다.

    memoizedState === null → visible
    memoizedState !== null → hidden
     
    - Activity가 hidden 상태가 되면 React는 해당 Fiber의 memoizedState에 OffscreenState 객체를 저장한다.
    Fiber(Activity)
       │
       └ Fiber(Offscreen)
            memoizedState = OffscreenState (hidden)
            │
            └ Fiber(ChatPanel)
    App
    ├ Header
    ├ Activity
    │  └ ChatPanel
    │     ├ MessageList
    │     └ Input
    └ Footer

    Activity는 Offscreen Fiber로 구현되며, hidden 상태일 때 memoizedState에 OffscreenState가 저장된다. React는 이를 통해 hidden 상태를 판단하고 subtree 렌더링을 스킵하지만, Fiber 구조 자체는 유지되기 때문에 subtree는 제거되지 않는다.

     

    Activity 사용은 그러면 언제? 

    - 뭐 대충 Activity가 이전값을 memoziedState에 OffsreenState에 저장되어 Fiber노드가 유지되어 유지가 된다는거는 알겠는데 이거를 언제 써야 잘 썼다고 소문이 날까?

    - 유튜브나 강의를 보면 Activity를 상태 조건에 따라 컴포넌트 렌더링 되는 모달? 같은 경우 사용하면 무작정 좋다고 하는데 이거는 아닌거 같다. 

    - 나도 처음은 그냥 오 편하고 좋네? 이 생각으로 있는 모달 모두 Activity처리헀는데 생각을 조금만 해보니 오히려 문제가 있을수도 있지 않을까? 생각이 들었다. 뭐 예를들어 잠깐 보여주는 모달 toast나 그런것들 까지 굳이?? 오히려 저 상태값을 저장하고 있는 메모리한테 미안하다 라는 생각이 들었다. 

    - 그래서 올바르게 사용하고자 한다면 유지가 되어야하는 유저 정보를 보여주는 모달? 같은 거나? 댓글모달 아니면 회원가입할때 유지되어야 하는 상태일때 사용하면 좋을거 같다. 

     

    • 회원가입 단계형 모달
    • 결제 단계 모달

    - 사람들이 그냥 좋다고 하는 것에는 항상 나쁜점도 있는거 같다. 항상 잘 알아보고 적절할때 스킬을 사용하면 더 멋진 개발자가 되지 않을까 생각이 들었다. 

     

Designed by Tistory.