当前位置: 首页 > article >正文

如何在React中服务器操作提交表单后(不)重置表单?

在 React 中使用服务器操作提交表单时,你可能会遇到这样一个问题:如何在服务器操作执行后(不)重置表单。这取决于你在 React 之上使用的框架,表单可能会自动重置,也可能需要你手动重置。

在 React 中,表单的默认行为是在提交操作后自动重置。无论表单提交是否成功,都会发生这种情况。当你在 React 之上使用 Next.js(因为你需要一个框架来使用服务器操作),这种默认行为并不会改变。

在本教程中,我将展示如何在服务器操作执行后保持表单状态不变。但这种情况仅适用于服务器操作失败时。如果服务器操作成功,表单应按常规方式重置。

大家也看到了,我将文章标题定为“如何在 React 中服务器操作提交表单后(不)重置表单”,是因为在早期的 React 版本中,默认行为与此相反。这时,你需要在服务器操作后手动重置表单。

如何在 React 中不重置表单

接下来我将从一个示例开始,在这个示例中,用户可以通过在 Next.js 中使用带有服务器操作的表单来创建帖子。当用户提交表单时,数据会被发送到服务器:

import { createPost } from "../actions/create-post";

const PostCreateForm = () => {
  return (
    <form action={createPost}>
      <label htmlFor="name">Name:</label>
      <input name="name" id="name" />

      <label htmlFor="content">Content:</label>
      <textarea name="content" id="content" />

      <button type="submit">Send</button>
    </form>
  );
};

该表单包含两个字段和一个提交按钮。当用户点击提交按钮时,会调用服务器操作,提取表单数据,并在数据库中创建一个帖子。如果表单提交成功,表单会自动重置:

"use server";

export const createPost = async (formData: FormData) => {
  const data = {
    name: formData.get("name"),
    content: formData.get("content"),
  };

  if (!data.name || !data.content) {
    throw new Error("Please fill in all fields");
  }

  // TODO: create post in database
};

但是,如果表单提交失败,原因是验证错误或数据库错误,用户就不得不重新输入数据,这显然不是很好的用户体验。我们可以通过在服务器操作中抛出一个错误来演示这一点,如果处理不当,这个错误将会导致应用程序崩溃。

通常,我们会使用 React 的 useActionState Hook 来处理服务器错误,并向用户显示一条消息。但是,这(目前)并不能阻止表单被重置:

"use client";

import { useActionState } from "react";
import { createPost } from "../actions/create-post";

const PostCreateForm = () => {
  const [actionState, action] = useActionState(createPost, {
    message: "",
  });

  return (
    <form action={action}>
      <label htmlFor="name">Name:</label>
      <input name="name" id="name" />

      <label htmlFor="content">Content:</label>
      <textarea name="content" id="content" />

      <button type="submit">Send</button>

      {actionState.message}
    </form>
  );
};

在服务器端,我们通常会捕获错误并向客户端返回一条消息。这里我为了简化操作,将直接返回这条消息:

"use server";

type ActionState = {
  message: string;
};

export const createPost = async (
  _actionState: ActionState,
  formData: FormData
) => {
  const data = {
    name: formData.get("name"),
    content: formData.get("content"),
  };

  if (!data.name || !data.content) {
    // throw new Error("Please fill in all fields");
    return { message: "Please fill in all fields" };
  }

  // TODO: create post in database

  return { message: "Post created" };
};

现在我们已经建立了基本设置。表单在服务器操作成功后会自动重置,如果服务器操作失败,则会显示错误消息。但在后者的情况下,表单数据会丢失。下面让我们通过防止表单在失败操作后重置来解决这个问题。

首先,如果表单提交失败,我们在服务器操作中返回表单数据:

"use server";

type ActionState = {
  message: string;
  payload?: FormData;
};

export const createPost = async (
  _actionState: ActionState,
  formData: FormData
) => {
  const data = {
    name: formData.get("name"),
    content: formData.get("content"),
  };

  if (!data.name || !data.content) {
    return {
      message: "Please fill in all fields",
      payload: formData,
    };
  }

  // TODO: create post in database

  return { message: "Post created" };
};

然后我们利用操作状态返回的表单数据,在服务器操作失败时,通过有条件地设置表单元素的默认值,来保持表单状态不变。

const PostCreateForm = () => {
  const [actionState, action] = useActionState(createPost, {
    message: "",
  });

  return (
    <form action={action}>
      <label htmlFor="name">Name:</label>
      <input
        name="name"
        id="name"
        defaultValue={(actionState.payload?.get("name") || "") as string}
      />

      <label htmlFor="content">Content:</label>
      <textarea
        name="content"
        id="content"
        defaultValue={(actionState.payload?.get("content") || "") as string}
      />

      <button type="submit">Send</button>

      {actionState.message}
    </form>
  );
};

现在,在服务器操作失败后,表单数据将保持不变。用户可以更正表单数据并重新提交,而无需重新输入数据。在服务器操作成功时,表单将按常规方式重置。


http://www.kler.cn/a/407176.html

相关文章:

  • Metasploit模块具体有哪些?
  • 根据已知站点寻找路网的最短路径
  • JDBC编程---Java
  • ubuntu20.04的arduino+MU编辑器安装教程
  • 使用 Maven 构建一个简单的 Java 项目
  • 大语言模型---LoRA中损失值的计算
  • Next.js 独立开发教程(三):CSS 样式的完整指南
  • OpenHands:开源AI编程工具的新贵,让编程更自然
  • Rust学习(七):智能指针
  • Vue前端进阶面试题目(二)
  • .NET9 - 新功能体验(二)
  • (udp)网络编程套接字Linux(整理)
  • 4、MAC地址、ARP协议解析
  • 【数据结构】—— 二叉树
  • 跨域相关的一些问题 ✅
  • CodiMD导出pdf失败或无中文
  • MySQL 中的锁
  • PHP实现插入排序
  • 解决 Docker Desktop 启动报错:Docker Desktop is unable to detect a Hypervisor
  • gpt2的学习
  • LVM缩容
  • Chrome DevTools Protocol 进阶:DOM 域
  • 开放性实验——网络安全渗透测试
  • Flutter实现气泡提示框学习
  • 设计模式-创建型-抽象工厂模式
  • Android kotlin之配置kapt编译器插件