useFormState
是一个可以根据某个表单动作的结果更新 state 的 Hook。
const [state, formAction] = useFormState(fn, initialState);
参考
useFormState(action, initialState)
在组件的顶层调用 useFormState
即可创建一个随 表单动作被调用 而更新的 state。在调用 useFormState
时在参数中传入现有的表单动作函数以及一个初始状态,它就会返回一个新的 action 函数和一个 form state 以供在 form 中使用。这个新的 form state 也会作为参数传入提供的表单动作函数。
import { useFormState } from "react-dom";
async function increment(previousState, formData) {
return previousState + 1;
}
function StatefulForm({}) {
const [state, formAction] = useFormState(increment, 0);
return (
<form>
{state}
<button formAction={formAction}>+1</button>
</form>
)
}
form state 是一个只在表单被提交触发 action 后才会被更新的值。如果该表单没有被提交,该值会保持传入的初始值不变。
如果配合 Server Action 一起使用,useFormState
允许与表单交互的服务器的返回值在 hydration 完成前显示。
参数
fn
:当按钮被按下或者表单被提交时触发的函数。当函数被调用时,该函数会接收到表单的上一个 state(初始值为传入的initialState
参数,否则为上一次执行完该函数的结果)作为函数的第一个参数,余下参数为普通表单动作接到的参数。initialState
:state 的初始值。任何可序列化的值都可接收。当 action 被调用一次后该参数会被忽略。
返回值
useFormState
返回一个包含两个值的数组:
- 当前的 state。第一次渲染期间,该值为传入的
initialState
参数值。在 action 被调用后该值会变为 action 的返回值。 - 一个新的 action 函数用于在你的
form
组件的action
参数或表单中任意一个button
组件的formAction
参数中传递。
注意
- 在支持 React 服务器组件的框架中使用该功能时,
useFormState
允许表单在服务器渲染阶段时获得部分交互性。当不使用服务器组件时,它的特性与本地 state 相同。 - 与直接通过表单动作调用的函数不同,传入
useFormState
的函数被调用时,会多传入一个代表 state 的上一个值或初始值的参数作为该函数的第一个参数。
用法
使用某个表单动作返回的信息
在组件的顶层调用 useFormState
以获取上一次表单被提交时触发的 action 的返回值。
import { useFormState } from 'react-dom';
import { action } from './actions.js';
function MyComponent() {
const [state, formAction] = useFormState(action, null);
// ...
return (
<form action={formAction}>
{/* ... */}
</form>
);
}
useFormState
返回一个包含两个值的数组:
- 该表单的 当前 state,初始值为提供的 初始 state,当表单被提交后则改为传入的 action 的返回值。
- 传入
<form>
标签的action
属性的 新 action。
表单被提交后,传入的 action 函数会被执行。返回值将会作为该表单的新的 当前 state。
传入的 action 接受到的第一个参数将会变为该表单的 当前 state。当表单第一次被提交时将会传入提供的 初始 state,之后都将传入上一次调用 action 函数的返回值。余下参数与未使用 useFormState
前接受的参数别无二致[1]。
function action(currentState, formData) {
// ...
return 'next state';
}
第 1 个示例 共 2 个挑战: 展示表单错误
将 action 包裹进 useFormState
即可展示诸如错误信息或 Server Action 返回的 toast 等信息。
import { useState } from "react"; import { useFormState } from "react-dom"; import { addToCart } from "./actions.js"; function AddToCartForm({itemID, itemTitle}) { const [message, formAction] = useFormState(addToCart, null); return ( <form action={formAction}> <h2>{itemTitle}</h2> <input type="hidden" name="itemID" value={itemID} /> <button type="submit">加入购物车</button> {message} </form> ); } export default function App() { return ( <> <AddToCartForm itemID="1" itemTitle="JavaScript:权威指南" /> <AddToCartForm itemID="2" itemTitle="JavaScript:优点荟萃" /> </> ) }