首页 > 解决方案 > 如何避免 React 表单中的数据重复

问题描述

在不使用任何库的情况下,我很难在 React 中获得一个简洁的代码来做一个简单的表单。

假设我有

import React, { useState } from 'react';

export const CreateUserForm = () => {
  const [firstName, setFirstName] = useState('');

  const userAddress = {};

  const handleAddressChange = ({ address, isValid }) => {
    userAddress = { ...address };
  };

  const subscribe = () => {
    createUser({firstName, userAddress}).then((response) => console.log(response));
  };

  return (
    <div>
      <input onChange={setFirstName}></input>
      <AddressForm onChange={handleAddressChange}></AddressForm>
      <button onClick={subscribe}></button>
    </div>
  );
};

在这里,我addressCreateUserForm组件中复制(addressAddressForm状态下管理)。

props我可以在组件中添加一些AddressForm,所以我最终会得到类似的东西:

import React, { useState } from 'react';

export const CreateUserForm = () => {
  const [firstName, setFirstName] = useState('');
  const [address, setAddress] = useState({});

  const handleAddressChange = ({ address, isValid }) => {
    setAddress({ ...address });
  };

  const subscribe = () => {
    createUser({firstName, userAddress}).then((response) => console.log(response));
  };

  return (
    <div>
      <input onChange={setFirstName}></input>
      <AddressForm address={address} onChange={handleAddressChange}></AddressForm>
      <button onClick={subscribe}></button>
    </div>
  );
};

所以在这里我不会复制,但每次地址更改时address我都会渲染整个组件,我错了吗?CreateUserForm

所以我觉得这些解决方案都不好,或者我错过了什么?第一个对我来说似乎更自然,但我有点重复信息..

什么是正确的方法?

标签: javascriptreactjs

解决方案


第二个选项是正确的选项,因为第一个选项可能不起作用,如果它起作用,那么如果您使 CreateUserForm 组件变得更复杂,就会有一些错误等待显示出来。

选项 1 没有正确使用状态并且很容易搞砸,因为 userAddress 不是有状态的。每次重新渲染组件时,它都会重置为 {}。为了使第一个选项起作用,您需要 useRef 来设置您的地址变量。

import React, { useState, useRef } from 'react';

export const CreateUserForm = () => {
  const [firstName, setFirstName] = useState('');

  const userAddress = useRef({});

  const handleAddressChange = ({ address, isValid }) => {
    userAddress.current = { ...address };
  };

  const subscribe = () => {
    createUser({firstName, userAddress: userAddress.current}).then((response) => console.log(response));
  };

  return (
    <div>
      <input onChange={setFirstName}></input>
      <AddressForm onChange={handleAddressChange}></AddressForm>
      <button onClick={subscribe}></button>
    </div>
  );
};

对第一个选项的这种更改将防止重新渲染,但代价是使 AddressForm 控制得更少。它还会阻止您将地址传递给组件的任何其他子级,因为它们不会重新渲染,因为除非您更改名字输入,否则父级也不会重新渲染。

每次在第二个选项中调用 handleAddressChange 时,CreateUserForm 组件肯定会重新渲染。通常在较小的应用程序中,重新渲染不会有性能问题。如果您开始遇到性能问题,请找出 CreateUserForm 的哪些子项需要一段时间来重新渲染和记忆它们(React.Memo 或 PureComponent),这样组件将快速重新渲染。尽管 memoization 还要求您确保传递给组件的内容在引用上是稳定的(即 useCallback 和 useRef)。

我通常检查表单是否渲染得足够快的方法是按住表单输入上的一个键,看看它是否以非生涩的方式重复。尽管该特定指标主要来自我的理想,并且并非所有应用程序都完全必要。

我知道您试图在没有表单库的情况下工作,但是react-hook-form似乎能够根据目的提供从完全不受控制到受控的范围,以保持性能并最大限度地减少过多的重新渲染。


推荐阅读