더이노베이터스

React 19 Actions로 재사용 가능한 컴포넌트 만들기

React 19에서는 사용자 경험을 향상시키기 위해 Actions, useTransition, useOptimistic과 같은 새로운 기능들이 도입되었다. 특히 비동기 처리를 다룰 때, 이 훅들은 기존의 상태 관리 방식보다 더 나은 사용자 인터페이스를 구축할 수 있도록 돕는다. 이번 글에서는 이 새로운 훅들의 차이점과 각각을 가장 효과적으로 사용할 수 있는 예제를 중심으로 설명한다.


기존의 상태 관리 훅 vs React 19의 새로운 훅

기존 훅들: useState, useEffect, useReducer

기존의 React 훅은 동기적인 상태 관리를 중심으로 작동한다. 예를 들어, 버튼을 클릭하면 setState를 통해 바로 상태가 업데이트되고 렌더링이 발생한다. 비동기 처리는 useEffectuseCallback 등으로 직접 제어해야 했기 때문에 사용자 경험 측면에서 불편함이 있었다.


useTransition: 느린 상태 업데이트를 비동기적으로 처리하기

useTransition은 사용자 인터페이스가 즉각 반응해야 하는 작업과 느려도 괜찮은 작업을 분리할 수 있도록 돕는 훅이다. startTransition 안에 감싼 상태 업데이트는 낮은 우선순위를 가지며, React는 이 업데이트를 가능한 한 나중에 처리한다. 이로 인해 UI는 빠르게 반응하면서도 느린 연산도 무리 없이 처리할 수 있다.

검색 기능에서 결과 필터링하기

jsx
복사편집
import { useState, useTransition } from 'react';

function Search() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  function handleChange(e) {
    const value = e.target.value;
    setQuery(value);

    startTransition(() => {
      // 예시용 필터링 로직
      const filtered = largeDataSet.filter(item =>
        item.toLowerCase().includes(value.toLowerCase())
      );
      setResults(filtered);
    });
  }

  return (
    <div>
      <input type="text" value={query} onChange={handleChange} />
      {isPending && <p>Loading...</p>}
      <ul>
        {results.map(result => (
          <li key={result}>{result}</li>
        ))}
      </ul>
    </div>
  );
}

이 예제에서는 입력값이 바뀔 때마다 즉시 입력 필드를 업데이트하고, 결과 필터링은 우선순위를 낮춰 UI 반응성을 확보했다.


useOptimistic: 낙관적 UI 업데이트

useOptimistic은 사용자 인터랙션 직후에 서버 응답을 기다리지 않고, 예상되는 결과를 먼저 보여주는 방식이다. 이를 통해 대기 시간 없이 부드러운 UX를 제공할 수 있다. 나중에 실제 응답이 오면 상태를 조정할 수 있다.

댓글 추가하기

import { useState, useOptimistic } from 'react';

function CommentList({ initialComments }) {
  const [comments, setComments] = useState(initialComments);
  const [optimisticComments, addOptimisticComment] = useOptimistic(
    comments,
    (state, newComment) => [...state, { id: 'temp', ...newComment }]
  );

  async function handleSubmit(text) {
    addOptimisticComment({ text });

    const savedComment = await postCommentToServer(text);
    setComments(prev => [...prev, savedComment]);
  }

  return (
    <div>
      <ul>
        {optimisticComments.map((comment, idx) => (
          <li key={idx}>{comment.text}</li>
        ))}
      </ul>
      <button onClick={() => handleSubmit('좋은 글이네요')}>댓글 달기</button>
    </div>
  );
}

여기서 useOptimistic은 댓글이 실제로 서버에 저장되기 전에 화면에 먼저 표시한다. 사용자 입장에서 기다림 없는 인터랙션을 경험할 수 있다.


차이점 요약

주요 기능사용 시점특징
useState동기 상태 업데이트모든 컴포넌트 내 상태 관리에 사용즉시 렌더링 발생
useTransition낮은 우선순위 상태 업데이트 처리느린 작업 (예: 필터링, 목록 정렬)UI 반응성 향상, 병렬적 처리 가능
useOptimistic낙관적 UI 업데이트서버 응답이 느릴 때 예상 결과 미리 표시사용자 경험 개선, 이후 동기화 처리 필요

결론

React 19의 useTransitionuseOptimistic은 사용자 경험을 부드럽게 만들기 위한 핵심 도구다. useTransition은 UI의 반응성을 해치지 않으면서 무거운 상태 업데이트를 처리할 수 있도록 해주고, useOptimistic은 즉각적인 피드백이 필요한 상황에서 대기 시간을 줄여준다. 이 훅들을 잘 조합하면 더 빠르고 직관적인 리액트 애플리케이션을 만들 수 있다.

TI Tech Lab 이유진 연구원

Source

Avatar

theinnovators

Add comment