Новый хук useOptimistic

Стартовый код. Форма которая меняет имя, и это занимает 3 секунды.

import { useState } from "react";

async function updateName(name) {
	console.log("updateName name:", name);
	console.log("Waiting 3 sec...");
	await new Promise((resolve) => {
		setTimeout(() => {
			resolve();
		}, 3000);
	});
	console.log("updateName COMPLETE");
	return name;
}

function App() {
	const [name, setName] = useState("John");

	async function handleSubmit(formData) {
		const newName = await updateName(formData.get("name"));
		setName(newName);
	}

	return (
		<form action={handleSubmit} className="card shadow p-3">
			<p className="fs-3">Current name: {name}</p>
			<label className="form-label">Enter name</label>
			<input name="name" className="form-control mb-3" />
			<button className="btn btn-dark">Update</button>
		</form>
	);
}

export default App;

Хук useOptimistic позволяет показать оптимистичный результат, не дожидаясь завершения выполнения action функции обработчика формы.

const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);

Код с использованием хука:

import { useState, useOptimistic } from "react";

async function updateName(name) {
	console.log("updateName name:", name);
	console.log("Waiting 3 sec...");
	await new Promise((resolve) => {
		setTimeout(() => {
			resolve();
		}, 3000);
	});
	console.log("updateName COMPLETE");
	return name;
}

function App() {
	const [name, setName] = useState("John");

	const [optimisticState, setOptimisticState] = useOptimistic(name);

	async function handleSubmit(formData) {
		setOptimisticState(formData.get("name"));
		const newName = await updateName(formData.get("name"));
		setName(newName);
	}

	return (
		<form action={handleSubmit} className="card shadow p-3">
			<p className="fs-3">Current name: {optimisticState}</p>
			<label className="form-label">Enter name</label>
			<input name="name" className="form-control mb-3" />
			<button
				className="btn btn-dark"
				disabled={name !== optimisticState}
			>
				Update
			</button>
		</form>
	);
}

export default App;

Использование updateFn в useOptimistic()

Тут рассмотрим пример из офф документации.

import { useOptimistic, useState, useRef } from "react";

async function deliverMessage(message) {
	await new Promise((res) => setTimeout(res, 4000));
	return message;
}

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} className="mb-1">
					{message.text}
					{!!message.sending && <small> (Sending...)</small>}
				</div>
			))}
			<form action={formAction} ref={formRef}>
				<input
					type="text"
					name="message"
					placeholder="Hello!"
					className="form-control mb-3"
				/>
				<button type="submit" className="btn btn-dark">
					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} />;
}