Новый хук useActionState

Чтобы упростить общие случаи для actions функций, был добавлен новый хук под названием useActionState

const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);

useActionState позволяет сразу получить состояние (его можно использовать для success уведомления или ошибки), создать action для обработки формы (он его принимает при вызове), и возвращает состояние isPending.

Функция, которую принимает useActionState должна иметь 2 параметра prevState и formData.

Рассмотрим на простом примере со счетчиком:

import { useActionState } from "react";

async function increment(previousState, formData) {
	return previousState + 1;
}

export default function App({}) {
	const [state, formAction] = useActionState(increment, 0);
	return (
		<form>
			<div className="fs-3 mb-2">{state}</div>
			<button formAction={formAction} className="btn btn-dark">
				Increment
			</button>
		</form>
	);
}

И на примере с формой обновления имени. Обратите внимание. Так как useActionState имеет состояние формы, то мы избавились от состояния success. И у нас теперь есть состояние формы в которое записывается информация об отправке формы. В этом состоянии может быть информация как об ошибке, так и о успехе.

import { useActionState } from "react";

async function updateName() {
	await new Promise((resolve) => {
		setTimeout(() => {
			resolve();
		}, 2000);
	});
	
	console.log("updateName COMPLETE");
	
	return {
		success: true,
		message: "Some error text",
	};
}

function App() {
	const [formState, submitAction, isPending] = useActionState(handleSubmit, null);

	async function handleSubmit (prevState, formData) {
		console.log(formData.get("name"));
		return await updateName(name);
	};

	function showSuccess() {
		return <div className="alert alert-success mb-3">Form submited!</div>;
	}

	return (
		<form action={submitAction} className="card shadow p-3">
			{formState?.success && showSuccess()}
			{formState?.success === false && <p>{formState.message}</p>}
			<label className="form-label">Enter name</label>
			<input name="name" className="form-control mb-3" />
			<button className="btn btn-dark" disabled={isPending}>
				Update
			</button>
		</form>
	);
}

export default App;