React.js

[React.js] useOptimistic에 대하여

도옹건 2025. 7. 20. 23:22

useOptimistic란? 

React 19에 새롭게 추가된 useOptimistic 훅은 낙관적 업데이트(Optimistic Updates)를 구현하기 위한 훅입니다. 사용자가 액션을 수행했을 때 서버 응답을 기다리지 않고 즉시 UI를 업데이트하여 더 나은 사용자 경험을 제공합니다.

 

낙관적 업데이트란?
- 즉시 UI 업데이트: 서버 응답을 기다리지 않고 UI를 먼저 변경
- 백그라운드 동기화: 동시에 서버에 요청을 보내 실제 데이터 업데이트
- 에러 처리: 실패 시 원래 상태로 되돌리기

 

예시코드

import { useOptimistic } from 'react';

function AppContainer() {
  const [optimisticState, addOptimistic] = useOptimistic(
    state,
    // updateFn
    (currentState, optimisticValue) => {
      // merge and return new state
      // with optimistic value
    }
  );
}

 

useOptimistic 훅의 매개변수와 반환값

  • 매개변수
    1. state (초기 상태)
     - 작업이 대기 중이지 않을 때 반환될 초기 상태값입니다.
    2. updateFn (업데이트 함수)
     - 현재 상태와 낙관적 값을 받아서 새로운 상태를 반환하는 순수 함수입니다.
    • 매개변수:
      currentState: 현재 상태
      optimisticValue: addOptimistic에 전달된 낙관적 값
  • 반환값
    1. optimisticState (낙관적 상태)
     - 낙관적 업데이트가 적용된 결과 상태입니다.

    2. addOptimistic (낙관적 업데이트 함수)
     - 낙관적 업데이트를 트리거하는 dispatch 함수입니다.

 

사용 예시

'use client';

import { useOptimistic, useState } from 'react';
import styles from './use-comment.module.css';

interface Comment {
  id: number;
  text: string;
  author: string;
  timestamp: string;
  pending?: boolean;
}

async function addComment(text: string, author: string): Promise<Comment> {
  await new Promise((resolve) => setTimeout(resolve, 1200));
  return {
    id: Date.now(),
    text,
    author,
    timestamp: new Date().toISOString(),
  };
}

export default function CommentOptimisticExample() {
  const [comments, setComments] = useState<Comment[]>([]);

  // 댓글 추가 낙관적 업데이트
  const [optimisticComments, addOptimisticComment] = useOptimistic(
    comments, // comments 값이 바뀌면 optimisticComments도 바뀜
    (state, newComment: Comment) => {
      return [...state, { ...newComment, pending: true }];
    },
  );

  const handleAddComment = async (formData: FormData) => {
    const text = formData.get('text') as string;
    const author = formData.get('author') as string;

    const newComment: Comment = {
      id: Date.now(),
      text,
      author,
      timestamp: new Date().toISOString(),
    };

    // 낙관적 업데이트
    addOptimisticComment(newComment);

    try {
      const result = await addComment(text, author);
      setComments((prev) => [...prev, result]);
    } catch (error) {
      console.error('댓글 추가 실패:', error);
      // 에러 시 원래 상태로 되돌리기
      setComments((prev) =>
        prev.filter((comment) => comment.id !== newComment.id),
      );
    }
  };

  console.log(optimisticComments);

  return (
    <div className={styles.container}>
      <h2>useOptimistic 댓글 예제</h2>
      <form action={handleAddComment} className={styles.commentForm}>
        <input
          name="author"
          placeholder="이름"
          className={styles.authorInput}
          required
        />
        <textarea
          name="text"
          placeholder="댓글을 입력하세요..."
          className={styles.commentInput}
          required
        />
        <button type="submit" className={styles.submitButton}>
          댓글 작성
        </button>
      </form>

      <div className={styles.commentList}>
        {optimisticComments.map((comment) => (
          <div
            key={comment.id}
            className={`${styles.commentItem} ${
              comment.pending ? styles.pending : ''
            }`}
          >
            <div className={styles.commentHeader}>
              <strong>{comment.author}</strong>
              <span className={styles.timestamp}>
                {new Date(comment.timestamp).toLocaleString()}
              </span>
              {comment.pending && (
                <span className={styles.pendingIndicator}>⏳</span>
              )}
            </div>
            <p className={styles.commentText}>{comment.text}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

동작 과정

1. 사용자가 댓글 입력 후 제출
   ↓
2. addOptimisticComment(newComment) 호출
   ↓
3. UI에 즉시 댓글 표시 (pending: true, ⏳ 표시)
   ↓
4. 백그라운드에서 addComment() 실행 (1.2초 소요)
   ↓
5. 서버 응답 후 setComments()로 실제 상태 업데이트
   ↓
6. pending 플래그 제거, ⏳ 표시 사라짐

 

 

 

참고

https://ko.react.dev/reference/react/useOptimistic

 

useOptimistic – React

The library for web and native user interfaces

ko.react.dev