В своем блоге Кент С. Доддс рассказал, как использовать новые хуки useFormStatus, useActionState и useOptimistic:
🌟 useFormStatus. Если вы знакомы с контекстом в React, то представьте, что тег form - это провайдер данных, а useFormStatus - это хук, который имеет доступ к данным провайдера. С помощью хука можно получить информацию о состоянии формы и переданных данных. Минус хука в том, что, чтобы его использовать, нужно создавать отдельный компонент, который должен быть вложен внутри form.
function JoinButton({ children }: { children: React.ReactNode }) {
const { pending, data } = useFormStatus()
return (
<button type="submit">
{pending ? `Joining as ${data.get('username')}...` : children}
</button>
)
}
function JoinEventForm() {
/** --snip */
return (
<form action={joinEvent}>
<JoinButton>Join</JoinButton>
</form>
)
}
🌟 useActionState. Этот хук позволяет обновить стейт по данным из формы. Разберем пример:
async function joinEvent(
previousState: { joined: boolean },
formData: FormData,
) {
/** --snip */
return { joined: true }
}
function JoinEventForm() {
const [state, formAction, isPending] = useActionState(
joinEvent,
{ joined: false },
JOIN_URL,
)
return (
<div>
{state.joined ? (
<p>See you there!</p>
) : (
<form action={formAction}>
<button type="submit">
{isPending ? 'Joining...' : 'Join'}
</button>
</form>
)}
</div>
)
}
Хук принимает функцию joinEvent, начальный стейт
{ joined: false } и опциональный параметр пермалинк JOIN_URL. Он возвращает массив с текущим стейтом, функцию триггера действия и флаг – находится ли форма в состоянии отправки. Обратите внимание, что функция joinEvent принимает первым аргументом предыдущее состояние. В каком-то смысле можно представить, что это редьюсер для useReducer. https://www.epicreact.dev/react-forms