본문 바로가기
TECH

상태 기반 렌더링 vs 시그널 기반 렌더링

by Stella-Park 2025. 12. 19.
728x90

React에서 상태 기반 렌더링 (State-based Rendering)시그널 기반 렌더링 (Signal-based Rendering)은 UI 업데이트 방식에서 큰 차이를 보인다. 두 개념을 비교하면서 자세히 설명하겠습니다.

 

 

상태 기반 렌더링 (State-based Rendering)

React의 전통적인 렌더링 방식입니다.

컴포넌트는 state나 props가 변경될 때 전체 컴포넌트를 다시 렌더링합니다.

React는 Virtual DOM을 사용해 변경된 부분만 실제 DOM에 반영하지만, 컴포넌트 함수는 다시 실행됩니다.

 

작동 방식

  • setState 또는 useState로 상태 변경
  • React는 해당 컴포넌트와 자식 컴포넌트를 다시 렌더링
  • Virtual DOM 비교 후 실제 DOM 업데이트

 

특징

  • 선언적 UI: State -> UI 자동 반영
  • 렌더링 단위: 컴포넌트 단위
  • 불필요한 렌더링 가능성 있음:  memo, useMemo, useCallback 등 최적화 필요
const [count, setCount] = useState(0)

return (
  <div>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>
      +
    </button>
  </div>
)

count가 바뀌면 컴포넌트 전체가 다시 렌더링됩니다.

 

 

시그널 기반 렌더링 (Signal-based Rendering)

최근 Solid.js, Qwik, React의 실험적 기능에서 주목받는 방식입니다.

UI는 반응형 원자 단위 데이터 (Signal)에 직접 연결됩니다.

변경된 시그널과 관련된 DOM만 업데이트되고, 컴포넌트 전체를 다시 실행하지는 않습니다.

 

작동 방식

  • 시그널은 getter / setter 형태로 값 추적
  • 값이 바뀌면 해당 DOM 바인딩만 업데이트
  • 컴포넌트 함수는 재실행되지 않음 -> 매우 빠름

 

특징

  • 렌더링 단위: DOM 노드 단위
  • 불필요한 렌더링 없음 -> 고성능
  • Reactdml useSignal (실험적) 또는 Solid.js의 createSignal과 유사
const count = createSignal(0)

return (
  <div>
    <p>{count()}</p>
    <button onClick={() => count(count() + 1)}>
      +
    </button>
  </div>
)

count()가 바뀌면 <p>만 업데이트되고, 컴포넌트 전체는 재실행되지 않습니다.

 

 

React 상태 기반 vs 시그널 기반 렌더링 코드 예제

// 상태 기반 렌더링 (React 기본)

import React, { useState } from 'react'

export default function StateBasedCounter() {
  const [count, setCount] = useState(0)

  console.log('Component re-rendered') // 상태 변경 시 전체 컴포넌트 재실행

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>
        +
      </button>
    </div>
  )
}
  • setCount 호출 시 컴포넌트 전체가 재렌더링
  • console.log가 매번 찍힘
// 시그널 기반 렌더링 (React 실험적 API, React 19 이상 useSignal API가 실험적으로 제공)

import { useSignal } from 'react'

export default function SignalBasedCounter() {
  const count = useSignal(0)

  console.log('Component rendered once') // 시그널 변경 시 재실행 없음

  return (
    <div>
      <p>{count.value}</p>
      <button onClick={() => count.value++}>
        +
      </button>
    </div>
  )
}
  • count.value가 바뀌어도 컴포넌트 함수는 재실행되지 않음
  • DOM바인딩된 부분만 업데이트 -> 매우 빠름

 

성능 차이 분석

 

측정 기준

  • 렌더링 횟수: 상태 기반은 변경 시마다 컴포넌트 재실행, 시그널 기반은 최초 1회
  • DOM 업데이트 비용: 상태기반은 Virtual DOM diff 필요, 시그널 기반은 직접 DOM 업데이트
  • 메모리 사용량: 상태 기반은 컴포넌트 재실행 시 메모리 할당 증가, 시그널 기반은 최소화

 

실제 시나리오

10,000개의 <Counter />컴포넌트가 있는 리스트에서 버튼 클릭

// 상태 기반
import React, { useState } from 'react'

function Counter({ id }: { id: number }) {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>
        Counter {id}: {count}
      </p>
      <button onClick={() => setCount(count + 1)}>
        +
      </button>
    </div>
  )
}

export default function StateBasedList() {
  const counters = Array.from({ length: 10000 }, (_, i) => i)

  return (
    <div>
      {counters.map((id) => (
        <Counter key={id} id={id} />
      ))}
    </div>
  )
}

 

 

728x90

 

// 시그널 기반

import { useSignal } from 'react'

function Counter({ id }: { id: number }) {
  const count = useSignal(0)

  return (
    <div>
      <p>
        Counter {id}: {count.value}
      </p>
      <button onClick={() => count.value++}>
        +
      </button>
    </div>
  )
}

export default function SignalBasedList() {
  const counters = Array.from({ length: 10000 }, (_, i) => i)

  return (
    <div>
      {counters.map((id) => (
        <Counter key={id} id={id} />
      ))}
    </div>
  )
}

 

 

 

  • X축: 컴포넌트 개수 (10, 100, 1,000, 10,000)
  • Y축: 총 렌더링 시간 (ms)
  • 파란색 (State-based): 컴포넌트 수가 많아질수록 선형적 증가
  • 초록색 (Signal-based): 훨씬 낮은 렌더링 시간 유지

 

10,000개 컴포넌트 기준

  • 상태 기반: 약 20,000ms (20초)
  • 시그널 기반: 약 2,000ms (2초)

10배 이상 빠름 / 규모가 커질수록 차이가 기하급수적으로 커짐

 

 

 

 

이상 스텔라였습니다 ✍🏻

 

 

 

 

 

 

 

 

728x90

'TECH' 카테고리의 다른 글

useOptimistic: React 19의 새로운 기능 🆕  (0) 2025.12.17
검색 파라미터 🔍  (0) 2025.12.15
5가지 노드 버전 관리자 비교  (0) 2025.12.04
아이콘 현지화 (localization)  (0) 2025.12.02
논리 할당 연산자  (0) 2025.11.20