前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在 React 表单开发时,有时没有必要使用State 数据状态

在 React 表单开发时,有时没有必要使用State 数据状态

作者头像
前端达人
发布2023-09-25 20:55:27
2680
发布2023-09-25 20:55:27
举报
文章被收录于专栏:前端达人前端达人

说到在React中处理表单,最流行的方法是将输入值存储在状态变量中。遵循这种方法的原因之一是因为毕竟它是React,每个人都倾向于使用它附带的hooks。使用hooks可以解决React中的许多问题,但是在处理表单时是否必需呢?让我们来看看。

使用“States”存在问题

正如我们已经知道的那样,每当组件内的状态变量的值发生变化时,React都会重新渲染组件以匹配其当前状态。虽然在小型应用程序中这不是一个大问题,但随着应用程序规模的增长,它可能导致性能瓶颈。当涉及到表单时,React会尝试在每次输入(状态)发生变化时重新渲染组件。

小提示:我在StackOverflow上找到了一个非常有用的答案,可以用来计算组件渲染的次数。我们也会在我们的代码中使用这个实用函数。

使用Vite创建一个基本的React应用,并在项目创建后清理掉不需要的文件。

代码语言:javascript
复制
npm create vite@latest my-vue-app  --template react

# yarn
yarn create vite my-vue-app --template react

# pnpm
pnpm create vite my-vue-app --template react

让我们创建一个 React 组件(称为 FormWithState ),其中包含一个表单,该表单接受两个输入:电子邮件和密码。我们将使用状态来管理表单输入。

代码语言:javascript
复制
import { useEffect, useRef, useState } from "react";
import "./Forms.css";

export default function FormWithState() {
  // The count will increment by 2 on initial render due to strict mode then by 1 on subsequent renders
  const countRef = useRef(0);
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  useEffect(() => {
    countRef.current = countRef.current + 1;
  });

  function handleSubmit(e) {
    e.preventDefault();
    console.log({ email, password });
  }

  return (
    <div className="form-div">
      <h2>Form With State</h2>
      <form onSubmit={handleSubmit}>
        <div className="input-field">
          <label htmlFor="email2">Email</label>
          <input
            id="email2"
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            autoComplete="off"
          />
        </div>
        <div className="input-field">
          <label htmlFor="password2">Password</label>
          <input
            id="password2"
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>
        <button type="submit">Submit</button>
        <div>
          <p>
            The Component Re-Rendered <span>{countRef.current}</span> times
          </p>
        </div>
      </form>
    </div>
  );
}

将此组件添加到 App 组件中,并打开 http://localhost:5173

正如你所看到的,表单组件大约被渲染了23次,随着输入字段数量的增加,这个数字会逐渐增加。在大多数情况下,表单值仅在表单提交时使用。那么,难道为了两个输入字段就需要重新渲染20多次的组件吗?答案是明确的:不需要!

此外,当输入字段的数量增加时,存储输入值的状态变量的数量也会增加,从而增加了代码库的复杂性。那么,有没有其他方法可以避免重新渲染,同时实现表单的所有功能呢?

使用FormData来处理表单

所以,另一种方法是使用JavaScript的原生 FormData 接口。根据官方文档的描述,创建一个新的 FormData 对象有三种方法。

代码语言:javascript
复制
new FormData();
new FormData(form);
new FormData(form, submitter);

我们将使用第二种方法,因为我们已经有一个表单。我们只需要将表单元素传递给构造函数,它将自动填充表单值。为了使其工作,我们还需要在 input 标签中添加 name 属性。让我们测试一下这种方法。创建一个组件(比如 FormWithoutState )。

代码语言:javascript
复制
import { useEffect, useRef } from "react";

export default function FormWithoutState() {
  // The count will increment by 2 on initial render due to strict mode then by 1 on subsequent renders
  const countRef = useRef(0);

  useEffect(() => {
    countRef.current = countRef.current + 1;
  });

  function handleSubmit(e) {
    e.preventDefault();
    const form = new FormData(e.currentTarget);
    const email = form.get("email");
    const password = form.get("password");
    console.log({ email, password });
    const body = {};
    for (const [key, value] of form.entries()) {
      body[key] = value;
    }
    console.log(body);
    // Do Further input validation and submit the form
  }

  return (
    <div className="form-div">
      <h2>Form Without State</h2>
      <form onSubmit={handleSubmit}>
        <div className="input-field">
          <label htmlFor="email1">Email</label>
          <input id="email1" type="email" name="email" autoComplete="off" />
        </div>
        <div className="input-field">
          <label htmlFor="password1">Password</label>
          <input id="password1" type="password" name="password" />
        </div>
        <button type="submit">Submit</button>
        <div>
          <p>
            The Component Re-Rendered <span>{countRef.current}</span> times
          </p>
        </div>
      </form>
    </div>
  );
}

在这个组件中,我们根本没有使用 useState hook。相反,我们将 name 属性添加到 input 标签中。一旦用户提交表单,在 handleSubmit 函数中,我们通过 e.currentTarget 提供表单对象来创建 FormData 。然后,我们通过 FormData.entries() 方法迭代获取表单的键和值来构建表单主体。我们可以使用这个对象进行进一步的输入验证和通过 fetch 或 Axios API进行提交。但是,这种方法对组件重新渲染的影响如何呢?让我们来看看。将这个组件添加到 App 组件中,并打开 http://localhost:5173 。

你难道不觉得惊讶吗?这个组件根本没有重新渲染。

使用FormData的优势

  • 表单输入值会自动捕获,无需为每个输入字段维护状态变量。
  • 使用 FormData 时,API请求体可以很容易地构建,而使用 useState 时,我们需要组装提交的数据。
  • 当表单增长时,它消除了引入新的状态变量的需求。
  • 处理多个表单时,您可能会发现在组件之间重复使用类似的状态变量,而 FormData 只需几行代码就可以轻松重用。
  • FormData 支持的一项功能是它会自动处理动态字段。即,如果您的表单具有动态生成的字段(根据用户输入添加/删除字段),使用 useState 管理它们的状态需要额外处理,而 FormData 会自动处理这些。

结束

您可以在 CodeSandbox 上查看此文章的代码,https://flx2nr.csb.app/,希望你从这篇文章中学到了一些新东西。如果有任何疑问,请留下评论。谢谢!

由于文章内容篇幅有限,今天的内容就分享到这里,文章结尾,我想提醒您,文章的创作不易,如果您喜欢我的分享,请别忘了点赞和转发,让更多有需要的人看到。同时,如果您想获取更多前端技术的知识,欢迎关注我,您的支持将是我分享最大的动力。我会持续输出更多内容,敬请期待。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-09-23 09:00,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用“States”存在问题
  • 使用FormData来处理表单
  • 使用FormData的优势
  • 结束
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档