useActionState - This feature is available in the latest Canary

Canary

useActionState Hook 目前仅在 React 的 Canary 和实验性通道中可用。请在此处详细了解发布渠道。此外,您需要使用支持React 服务器组件的框架才能充分利用 useActionState

注意

在早期版本的 React Canary 中,此 API 是 React DOM 的一部分,名为 useFormState

useActionState 是一个 Hook,允许您根据表单操作的结果更新状态。

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

参考

useActionState(action, initialState, permalink?)

在组件的顶层调用 useActionState,以创建在调用表单操作时更新的组件状态。您需要向 useActionState 传递一个现有的表单操作函数以及一个初始状态,它会返回一个新的操作(您将在表单中使用该操作)以及最新的表单状态。最新的表单状态也会传递给您提供的函数。

import { useActionState } from "react";

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

function StatefulForm({}) {
const [state, formAction] = useActionState(increment, 0);
return (
<form>
{state}
<button formAction={formAction}>Increment</button>
</form>
)
}

表单状态是上次提交表单时操作返回的值。如果表单尚未提交,则它就是您传递的初始状态。

如果与服务器操作一起使用,useActionState 允许在完成水合之前显示提交表单的服务器响应。

请参阅下面的更多示例。

参数

  • fn:提交表单或按下按钮时要调用的函数。调用该函数时,它将接收表单的先前状态(最初是您传递的 initialState,随后是其先前的返回值)作为其初始参数,然后是表单操作通常接收的参数。
  • initialState:您希望状态最初具有的值。它可以是任何可序列化的值。首次调用该操作后,将忽略此参数。
  • **可选** permalink:包含此表单修改的唯一页面 URL 的字符串。用于具有动态内容的页面(例如:feed)以及渐进增强:如果 fn服务器操作并且在 JavaScript 包加载之前提交了表单,则浏览器将导航到指定的永久链接 URL,而不是当前页面的 URL。确保在目标页面上呈现相同的表单组件(包括相同的操作 fnpermalink),以便 React 知道如何传递状态。表单水合后,此参数无效。

返回值

useActionState 返回一个包含两个值的数组

  1. 当前状态。在第一次渲染期间,它将与您传递的 initialState 匹配。调用操作后,它将与操作返回的值匹配。
  2. 您可以作为 action 属性传递给 form 组件或作为 formAction 属性传递给表单中任何 button 组件的新操作。

注意事项

  • 当与支持 React 服务器组件的框架一起使用时,useActionState 允许您在客户端执行 JavaScript 之前使表单具有交互性。当在没有服务器组件的情况下使用时,它等同于组件本地状态。
  • 传递给 useActionState 的函数接收一个额外的参数,即先前的或初始状态,作为其第一个参数。这使得它的签名与在不使用 useActionState 的情况下直接用作表单操作时不同。

用法

使用表单操作返回的信息

在组件的顶层调用 useActionState,以访问上次提交表单时操作的返回值。

import { useActionState } from 'react';
import { action } from './actions.js';

function MyComponent() {
const [state, formAction] = useActionState(action, null);
// ...
return (
<form action={formAction}>
{/* ... */}
</form>
);
}

useActionState 返回一个恰好包含两个项目的数组

  1. 表单的当前状态,最初设置为您提供的初始状态,并在提交表单后设置为您提供的操作的返回值。
  2. 您传递给 <form>新操作作为其 action 属性。

当提交表单时,将调用您提供的操作函数。其返回值将成为表单的新的当前状态

您提供的操作还将接收一个新的第一个参数,即表单的当前状态。第一次提交表单时,这将是您提供的初始状态,而在后续提交中,它将是上次调用操作时的返回值。其余的参数与未使用 useActionState 时相同。

function action(currentState, formData) {
// ...
return 'next state';
}

提交表单后显示信息

示例 1 2:
显示表单错误

要显示消息(例如服务器操作返回的错误消息或 Toast),请将操作包装在对 useActionState 的调用中。

import { useActionState, useState } from "react";
import { addToCart } from "./actions.js";

function AddToCartForm({itemID, itemTitle}) {
  const [message, formAction] = useActionState(addToCart, null);
  return (
    <form action={formAction}>
      <h2>{itemTitle}</h2>
      <input type="hidden" name="itemID" value={itemID} />
      <button type="submit">Add to Cart</button>
      {message}
    </form>
  );
}

export default function App() {
  return (
    <>
      <AddToCartForm itemID="1" itemTitle="JavaScript: The Definitive Guide" />
      <AddToCartForm itemID="2" itemTitle="JavaScript: The Good Parts" />
    </>
  )
}

故障排除

我的操作无法再读取提交的表单数据

当您使用 useActionState 包装操作时,它会获得一个额外的参数,作为其第一个参数。因此,提交的表单数据是其第二个参数,而不是像往常那样是第一个参数。添加的新第一个参数是表单的当前状态。

function action(currentState, formData) {
// ...
}