如何用函数组件解决 React 中的不受控组件问题?

Posted

技术标签:

【中文标题】如何用函数组件解决 React 中的不受控组件问题?【英文标题】:How to solve Uncontrolled Component problem in React with Function Component? 【发布时间】:2021-12-19 06:44:42 【问题描述】:

我正在制作表单组件。(它是功能组件) 它是不受控制的组件,因为我不想在Input 组件中进行不必要的渲染。 但它有一个意想不到的词。

    我尝试在Input 组件中使用setState() 设置值并通过值道具onChange。它不是将整个值从 Input 传递到 Form

    我不想要不必要的渲染。但是,当我在电子邮件中输入值时,会同时使用密码对渲染做出反应。

我该如何解决这个问题?

代码沙盒链接 https://codesandbox.io/s/makewelldonecomponents-txxl0?file=/src/Input.js

或代码

(输入组件)

import React,  useEffect, useState  from "react";

const Input = ( type, placeholder, onChange ) => 
  const [value, setValue] = useState("");

  function handleChange(e) 
    setValue(e.target.value);
    onChange(value);
  

  return (
    <>
      console.log("render", placeholder)
      <input placeholder=placeholder value=value onChange=handleChange />
    </>
  );
;

export default Input;

(表单组件)

import React,  useState, useEffect  from "react";
import Input from "./Input";

const Form = () => 
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [state, setState] = useState(0);

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

  function handleEmail(value) 
    setEmail(value);
    console.log(value);
  

  function handlePassword(value) 
    setPassword(value);
  

  function handleReset(e) 
    setEmail("");
    setPassword("");
    setState(state + 1);
  

  return (
    <form onSubmit=handleSubmit>
      <Input
        key=state + "email"
        type="email"
        placeholder="이메일"
        onChange=handleEmail
      />
      <Input
        key=state + "password"
        type="password"
        placeholder="비밀번호"
        onChange=handlePassword
      />
      <button type="submit">가입</button>
      <button type="button" onClick=handleReset>
        초기화
      </button>
    </form>
  );
;

export default Form;

【问题讨论】:

【参考方案1】:
    Input 组件中使用useRef 而不是useState
import React,  useRef  from "react";

const Input = ( type, placeholder, onChange ) => 
  const valRef = useRef("");

  function handleChange(e) 
    valRef.current = e.target.value;
    onChange(valRef.current);
  

  return (
    <>
      console.log("render", placeholder)
      <input
        placeholder=placeholder
        value=valRef.current
        onChange=handleChange
      />
    </>
  );
;

export default Input;

    使用useCallbackhandleEmailhandlePassword 函数

  const handleEmail = useCallback((value) => 
    setEmail(value);
    console.log(value);
  , []);

【讨论】:

感谢您的回答。我还有一个问题。当我第一次渲染组件时,useCallback 只渲染了一次。正确的?所以,你回答 Q2。但是,我用 useCallback 重写了我的代码,但在 handleEmail、handlePassword 中仍然是不必要的渲染。这是不可避免的工作吗?【参考方案2】:

您可以在 React 中实现不受控制的表单,而无需使用状态和多个更改处理程序。

这是更新后的沙盒:

Form组件:

const Form = () => 
  const email = useRef(null);
  const password = useRef(null);

  function handleSubmit(e) 
    e.preventDefault();
    console.log(email.current.value, password.current.value);
  

  return (
    <form onSubmit=handleSubmit>
      <Input type="email" placeholder="이메일" ref=email />
      <Input type="password" placeholder="비밀번호" ref=password />
      <button type="submit">가입</button>
      <button type="reset">초기화</button>
    </form>
  );
;

export default Form;

Input组件:

import React,  forwardRef  from "react";

const Input = forwardRef((props, ref) => 
  return <input ...props ref=ref />;
);

【讨论】:

好答案。但是,我需要了解 Q2。当我输入电子邮件或密码时,如何知道只渲染一个组件? @Aaaaaa 在上面的实现中,输入电子邮件/密码时没有重新渲染任何输入组件

以上是关于如何用函数组件解决 React 中的不受控组件问题?的主要内容,如果未能解决你的问题,请参考以下文章

react input受控组件——函数柯里化

react input受控组件——函数柯里化

react input受控组件——函数柯里化

React之事件处理之受控组件和非受控组件以及函数柯里化

React面向组件编程 - 基本理解和使用 - 组件三大核心属性state-props-refs - 事件处理 - 非受控组件 - 受控组件 - 高阶函数 - 函数柯里化

react组件的分类大全,以及受控组件和非受控组件