useOptimistic은 UI를 낙관적으로 업데이트할 수 있는 React Hook이다.
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
useOptimistic은 비동기 작업이 진행되는 동안 다른 상태를 표시할 수 있는 React Hook이다. state를 인수로 받아들이고 네트워크 요청과 같은 비동기 작업이 지속 되는 동안 다를 수 있는 해당 상태의 복사본을 반환한다.현재 state와 action에 대한 입력을 가져와 작업이 pending 상태인 동안 낙관적 상태를 반환하는 함수를 제공한다.
이 상태를 "optimisitc" state라고 부르는 이유는 작업이 실제로 완료되는 데 시간이 걸리더라도 일반적으로 사용자에게 작업 수행 결과를 즉시 제공하는 데 사용되기 때문이다.
import { useOptimistic } from 'react';
function AppContainer() {
const [optimisticState, addOptimistic] = useOptimistic(
state,
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value
}
);
}
낙관적으로 form 업데이트
useOptimistic Hook은 네트워크 요청과 같은 백그라운드 작업이 완료되기 전에 사용자 인터페이스를 낙관적으로 업데이트하는 방법을 제공한다. form의 맥락에서 이 기술은 앱의 반응성을 높이는 데 도움이 된다. 사용자가 form을 제출하고 서버의 응답이 변경사항을 반영할 때 까지 기다리는 대신 예상되는 결과로 UI를 즉시 업데이트한다.
예를 들어, 사용자가 form에 메세지를 입력하고 전송 버튼을 누르면 useOptimistic Hook은 메시지가 실제로 서버로 전송되기 전에도 메시지가 "보내는 중..." 레이블과 함께 목록에 즉시 표시되도록 허용한다. 서버에서 메시지 수신을 확인하면 '보내는 중...' 라벨이 제거된다.
App.js
import { useOptimistic, useState, useRef } from "react";
import { deliverMessage } from "./actions.js";
function Thread({ messages, sendMessage }) {
const formRef = useRef();
async function formAction(formData) {
addOptimisticMessage(formData.get("message"));
formRef.current.reset();
await sendMessage(formData);
}
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [
...state,
{
text: newMessage,
sending: true
}
]
);
return (
<>
{optimisticMessages.map((message, index) => (
<div key={index}>
{message.text}
{!!message.sending && <small> (Sending...)</small>}
</div>
))}
<form action={formAction} ref={formRef}>
<input type="text" name="message" placeholder="Hello!" />
<button type="submit">Send</button>
</form>
</>
);
}
export default function App() {
const [messages, setMessages] = useState([
{ text: "Hello there!", sending: false, key: 1 }
]);
async function sendMessage(formData) {
const sentMessage = await deliverMessage(formData.get("message"));
setMessages((messages) => [...messages, { text: sentMessage }]);
}
return <Thread messages={messages} sendMessage={sendMessage} />;
}
actions.js (서버에 1초라는 시간이 걸린다고 예시로 만들어놓은 코드)
export async function deliverMessage(message) {
await new Promise((res) => setTimeout(res, 1000));
return message;
}
위에 코드를 보면 Thread 컴포넌트에 formAction 함수에서 서버에 메세지를 전송하는 sendMessage 함수를 호출하기 전에 낙관적 상태 업데이트 함수인 addOptimisticMessage 호출하여 상태를 업데이트한다. 실제로 반환문에서 optimisticMessages.map문을 사용하여 코드를 출력하므로 서버에 요청이 완료되기 전에도 전송하는 메시지 텍스트가 반영된다.