리액트 공식 문서를 참고한 정리 내용 (25.08 기준)
UI를 낙관적으로 업데이트할 수 있게 해주는 Hook이다.
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
네트워크 요청이나 비동기 작업 때문에 사용자가 결과를 바로 보지 못하고 기다려야 하는 경우가 많은데, 이걸 보는 사용자는 답답할 수 있다. 이럴 때 사용하는 게 useOptimistic 훅이다
이름 그대로 “낙관적인 상태(optimistic state)”를 보여주는 훅이다. 즉, 작업이 끝날 때까지 기다리지 않고 마치 이미 성공할 것처럼 결과를 화면에 먼저 보여줄 수 있도록 도와주는 역할을 수행한다.
역할 수행 방식은 (1)현재 상태와 작업 입력값을 받는다.그리고 (2)비동기 작업이 진행되는 동안, “낙관적인 상태”라는 가짜 복사본을 만들어서 반환한다. 마지막으로 (3)실제 작업이 끝나면 진짜 상태로 교체된다.
import { useOptimistic } from 'react';
function AppContainer() {
const [optimisticState, addOptimistic] = useOptimistic(
state,
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value
}
);
}
stateudateFn(currentState, optimisticValue)optimisticValue은 함수에 전달한 새로운 값이며, currentState와 합쳐서 “낙관적인 결과 상태”를 만들어서 반환하면 된다.👉 updateFn은 "기존 상태 + 새 값 = 낙관적인 상태" 로 만드는 함수 |
const [optimisticComments, addOptimisticComment] = useOptimistic(
[], // state: 기본 상태 → 처음엔 빈 배열
(currentComments, newComment) => [...currentComments, newComment]
// updateFn: 지금까지 댓글 + 새 댓글을 합쳐서 반환
);
optimisticState
state)를 보여준다. 작업이 진행 중이면 updateFn이 만들어낸 가짜 상태(optimistic)를 보여준다.addOptimistic
optimisticValue (ex. 새 댓글, 좋아요 누름 등)를 넘기면 state와 합쳐져서 optimisticState가 업데이트 된다보통은 사용자가 폼을 제출하면 → 서버에 요청을 보낸 뒤 → 응답이 돌아올 때까지 기다려야 화면이 업데이트 된다.
하지만 이렇게 하면 사용자 입장에서는 “버튼 눌렀는데 왜 바로 반응이 없지?"하고 답답할 수 있다.
이럴 때 useOptimistic을 사용하면, 서버 응답을 기다리지 않고도 먼저 화면을 바꿔 보여줄 수 있다. 마치 결과를 미리 예측해서 보여주는(=낙관적인) 방식이다.
메시지 전송을 예시로 들어보자
import { useState, useOptimistic } from "react";
function CommentForm({ onAdd }) {
const [text, setText] = useState("");
// 낙관적 상태 관리: 새로운 댓글을 바로 UI에 추가
const [optimisticComments, addOptimisticComment] = useOptimistic(
[],
(state, newComment) => [...state, newComment]
);
async function handleSubmit(e) {
e.preventDefault();
const comment = { id: Date.now(), text };
// 낙관적 업데이트 (서버 응답 기다리기 전에 먼저 추가)
addOptimisticComment(comment);
// 실제 서버 저장 요청
await onAdd(comment);
setText("");
}
return (
<form onSubmit={handleSubmit}>
<input
value={text}
onChange={e => setText(e.target.value)}
placeholder="Write a comment"
/>
<button type="submit">Add</button>
<ul>
{optimisticComments.map(c => (
<li key={c.id}>{c.text}</li>
))}
</ul>
</form>
);
}
이러한 점은 사용자 입장에서 어플리케이션이 빠르게 느껴지고, 네트워크 지연이 있어도 “즉시 반응”하는 것처럼 보이니까 UX가 매끄러워진다.