누구나 로고
オンライン講座企業・団体研修ライブラリトレンドインサイト無料コースお知らせお問い合わせ採用サイト
모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.
로그인무료 회원가입
강좌리액트 입문 — 컴포넌트로 만드는 웹24강

24강 / 전체 28강

비동기 상태 관리 패턴

5분 읽기 조회 0

리액트 18의 핵심 기능인 동시성 렌더링(Concurrent Rendering), useTransition, useDeferredValue의 동작 원리와 실전 사용법을 배웁니다.

⚡ 리액트 18 — 동시성의 시대

리액트 18은 동시성 렌더링(Concurrent Rendering)을 도입했습니다. 이것은 리액트의 렌더링 방식을 근본적으로 바꾼 업그레이드입니다. 이전에는 렌더링이 시작되면 완료될 때까지 중단할 수 없었습니다. 무거운 렌더링이 발생하면 UI가 멈추는(jank) 현상이 생겼습니다.

동시성 렌더링은 렌더링을 일시 중지하고 재개하며 우선순위를 부여할 수 있습니다. 긴급한 업데이트(사용자 입력)와 덜 긴급한 업데이트(검색 결과)를 구분해서 처리합니다.

🔄 useTransition — 긴급하지 않은 업데이트 표시

검색창에서 타이핑할 때마다 수천 개의 결과를 필터링하면 타이핑이 버벅거립니다. useTransition은 필터링 업데이트를 "긴급하지 않음"으로 표시해, 타이핑(긴급)이 먼저 처리되도록 우선순위를 부여합니다:

import { useState, useTransition, memo } from 'react'

// 수천 개 아이템 리스트 (일부러 무겁게)
const BigList = memo(function BigList({ filter }: { filter: string }) {
  const items = Array.from({ length: 10000 }, (_, i) => `아이템 ${i + 1}`)
    .filter((item) => item.includes(filter))

  return (
    <ul className="h-64 overflow-y-auto space-y-0.5">
      {items.map((item, i) => (
        <li key={i} className="px-3 py-1 text-sm text-gray-700">{item}</li>
      ))}
    </ul>
  )
})

function SearchWithTransition() {
  const [query, setQuery] = useState('')
  const [filter, setFilter] = useState('')  // BigList에 내려줄 값
  const [isPending, startTransition] = useTransition()

  function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    const value = e.target.value
    setQuery(value)  // 입력창 업데이트 — 즉시 (긴급)

    // 필터링 업데이트 — 느려도 되는 것 (비긴급)
    startTransition(() => {
      setFilter(value)
    })
  }

  return (
    <div>
      <div className="relative">
        <input
          value={query}
          onChange={handleChange}
          placeholder="검색..."
          className="border rounded-lg px-4 py-2 w-full"
        />
        {isPending && (
          <span className="absolute right-3 top-2.5 text-xs text-gray-400">필터링 중...</span>
        )}
      </div>
      <BigList filter={filter} />
    </div>
  )
}

startTransition 안의 상태 업데이트는 우선순위가 낮아집니다. 타이핑 중에는 입력창이 즉시 반응하고, 목록 필터링은 타이핑이 멈출 때 처리됩니다.

⏳ useDeferredValue — 값 기반 지연

useDeferredValue는 useTransition과 비슷하지만, 상태 setter 대신 값을 지연합니다. 외부에서 받은 값(Props)을 지연할 때 유용합니다:

import { useDeferredValue, useMemo } from 'react'

function FilterableList({ query }: { query: string }) {
  // query가 빠르게 바뀌어도 deferredQuery는 여유롭게 업데이트
  const deferredQuery = useDeferredValue(query)

  const filteredItems = useMemo(() => {
    return Array.from({ length: 10000 }, (_, i) => `아이템 ${i + 1}`)
      .filter((item) => item.includes(deferredQuery))
  }, [deferredQuery])  // deferredQuery가 바뀔 때만 재계산

  const isStale = query !== deferredQuery  // 오래된 값이면 true

  return (
    <ul style={{ opacity: isStale ? 0.7 : 1, transition: 'opacity 0.2s' }}>
      {filteredItems.map((item, i) => (
        <li key={i}>{item}</li>
      ))}
    </ul>
  )
}

목록이 오래된 값을 보여줄 때 살짝 흐리게 만들어 사용자에게 업데이트 중임을 알릴 수 있습니다.

🆚 useTransition vs useDeferredValue

구분useTransitionuseDeferredValue
제어 위치상태 업데이트 하는 곳값을 소비하는 곳
언제 사용자신이 상태를 바꿀 수 있을 때Props로 받은 값을 지연할 때
isPending 접근가능직접 비교 필요 (query !== deferredQuery)

✅ 정리

  • 리액트 18의 동시성 렌더링: 우선순위를 부여해 긴급한 업데이트 먼저 처리.
  • useTransition: 느려도 되는 상태 업데이트를 startTransition으로 감쌉니다.
  • useDeferredValue: Props 값을 지연해서 받아 무거운 렌더링을 늦춥니다.
  • 두 API 모두 측정 후 필요할 때만 사용 — 대부분의 앱에서는 필요하지 않습니다.

관련 주제

  • 데이터 페칭 로딩 에러 성공 상태
  • 재시도 로직
  • 스피너 토스트 피드백
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 리액트 입문 — 컴포넌트로 만드는 웹
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나
이전 23강리스트·상세 페이지 연결다음 25강 성능 기초 — memo

댓글

0/1000

불러오는 중...

목차

  1. 1.리액트란 무엇인가
  2. 2.개발 환경 만들기 — Vite
  3. 3.JSX 기초
  4. 4.컴포넌트 만들기
  5. 5.Props로 데이터 전달
  6. 6.State와 useState
  7. 7.이벤트 처리
  8. 8.조건부 렌더링
  9. 9.리스트 렌더링과 key
  10. 10.폼 다루기
  11. 11.useEffect 기초
  12. 12.데이터 가져오기(fetch)
  13. 13.상태 끌어올리기
  14. 14.컴포넌트 합성과 재사용
  15. 15.useRef와 DOM 접근
  16. 16.커스텀 훅 만들기
  17. 17.Context API
  18. 18.useReducer
  19. 19.리스트 앱 실전 ①
  20. 20.리스트 앱 실전 ②
  21. 21.라우팅 — React Router
  22. 22.스타일링 방법들
  23. 23.리스트·상세 페이지 연결
  24. 24.비동기 상태 관리 패턴
  25. 25.성능 기초 — memo
  26. 26.에러 처리와 경계
  27. 27.환경변수와 빌드
  28. 28.배포하기

カスタマーサポート

  • お知らせ
  • よくある質問
  • お問い合わせ
  • コミュニティ

ご利用案内

  • 利用規約
  • プライバシーポリシー
  • 返金ポリシー

サービス

  • 会社紹介
  • 新規登録
  • 新着コース
  • 無料コース
누구나 로고
利用規約プライバシーポリシー返金ポリシー

상호명: NUGUNA  |  대표자: 정우진  |  사업자등록번호: 392-32-01817  |  통신판매업신고: 제 2026-서울양천-0564 호

주소: 서울특별시 양천구 목동서로 100  |  이메일: nugunapass@gmail.com  |  전화: 010-6395-3043

© 2026 NUGUNA. All rights reserved.

KB예금주인증관리자
ホームコースライブラリお問い合わせMY