React 19 表单处理新方式-新Hooks
我们在使用 React 处理表单给服务器发送数据的时候,需要分别手动处理 Loading 加载,error 错误,和服务器请求,这样的 state 比较分散,代码不容易维护:
function CommentForm() {
const [comments, setComments] = useState([]);
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
async function handleFormSubmit(e) {
e.preventDefault();
setIsPending(true);
const formData = new FormData(e.target);
const comment = formData.get("comment");
try {
const result = await submitComment(comment);
setComments((comments) => [...comments, result]);
setIsPending(false);
} catch (error) {
setError(error);
}
}
React 19 出了一个新 Hooks, useActionState 可以让我们集中管理 loading、error 和服务器的请求,它:
- 接收一个 async 的函数作为参数,在里边我们可以编写表单的提交操作。
- 这个函数又接收两个参数,一个是表单之前的状态,一个是React 帮我们包装好的表单对象,基于浏览器的 FormData API,它包含各个表单控件的用户输入。
- 之后在里边我们可以访问表单数据并提交到服务器。
- 函数的返回值会作为 useActionState 的返回值之一,一般用于返回错误。
- 最后 useActionState 还接收第二个参数,作为表单状态的初始值。
- useActionState 会返回一个数组,它里边有我们 async 函数的返回值,用于给表单 action 属性绑定的事件处理函数,还有一个加载状态。
这样定义好之后,我们就可以在 JSX 中使用了:
const [error, submitCommentAction, isPending] = useActionState(
async (previousState, formData) => {
const comment = formData.get("comment");
const result = await submitComment(comment);
setComments((comments) => [...comments, result]);
return null;
},
null
);
<form action={submitCommentAction}>
<textarea
name="comment"
placeholder="写个评论吧..."
cols={40}
rows={4}
/>
<button type="submit" disabled={isPending}>
发布评论
</button>
</form>
{error && <p className="error">{error}</p>}
<ul className="comments-list">
{comments.map((comment, index) => (
<li key={index}>
<p>评论:{comment}</p>
</li>
))}
</ul>
在表单提交后,React 现在还会帮我们自动清空表单控件的里的输入,只要这些输入框是非受控组件。
乐观 UI
另外,表单处理还有另外一种常见的需求,就是乐观 UI,在提交数据后,先更新 UI,随后再处理服务器数据,这样能先给用户反馈,提高程序响应性。
React 19 提供了 useOptimistic Hooks 来实现乐观 UI,我们可以:
- 使用它包装一下表单本身的状态。
- 它会返回和 useState 类似的两个结果,一个是乐观状态值,一个是修改乐观状态的函数。
- 之后我们在表单处理函数里,调用修改乐观状态的函数就可以了,可以在发送服务器数据之前。
- 最后在 JSX 中,使用乐观数据展示就可以了。
const [optimisticComments, setOptimisticComents] = useOptimistic(comments);
const [error, submitCommentAction, isPending] = useActionState(
async (previousState, formData) => {
const comment = formData.get("comment");
setOptimisticComents((optComments) => [...optComments, comment]);
const result = await submitComment(comment);
setComments((comments) => [...comments, result]);
return null;
},
null
);
<ul className="comments-list">
{optimisticComments.map((comment, index) => (
<li key={index}>
<p>评论:{comment}</p>
</li>
))}
</ul>
访问上层表单状态
有时候表单组件的嵌套比较复杂,每个表单控件可能都是一个独立的组件,这样在获取表单状态的时候,需要多次传递 props,很不方便,这个时候 React 19 提供了 useFormStatus hooks,只要是 form 元素下层的组件,都可以访问表单的状态,例如加载状态、数据和错误等等,调用 useFormStatus 会返回包含这些信息的对象,例如我们可以在按钮中访问表单的加载状态,然后根据它来判断是否禁用按钮,之后父组件也不用再传递props了:
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
发布评论
</button>
);
}
<form action={submitCommentAction}>
<!-- ... -->
<SubmitButton />
</form>
小结
好了,这个就是 React 19 表单处理的新方式,以及相关的 hooks,你学会了吗?如果有帮助请三连并关注,想学更多的开发知识,可以在评论区留言,感谢观看!
一系列的课程让你成为高级前端工程师。课程覆盖工作中所有常用的知识点和背后的使用逻辑,示例全部都为工作项目简化而来,学完即可直接上手开发!
即使你已经是高级前端工程师,在课程里也可能会发现新的知识点和技巧,让你的工作更加轻松!
《React 完全指南》课程,包含 React、React Router 和 Redux 详细介绍,所有示例改编自真实工作代码。点击查看详情。
《Vue 3.x 全家桶完全指南与实战》课程,包括 Vue 3.x、TypeScript、Vue Router 4.x、Vuex 4.x 所有初级到高级的语法特性详解,让你完全胜任 Vue 前端开发的工作。点击查看详情。
《React即时通信UI实战》课程,利用 Storybook、Styled-components、React-Spring 打造属于自己的组件库。
《JavaScript 基础语法详解》本人所著图书,包含 JavaScript 全面的语法知识和新特性, 可在京东、当当、淘宝等各大电商购买