受控组件和非受控组件的区别?别再傻傻分不清了 😁😁😁

面试导航 是一个专注于前、后端技术学习和面试准备的 免费 学习平台,提供系统化的技术栈学习,深入讲解每个知识点的核心原理,帮助开发者构建全面的技术体系。平台还收录了大量真实的校招与社招面经,帮助你快速掌握面试技巧,提升求职竞争力。如果你想加入我们的交流群,欢迎通过微信联系:yunmz777

在 React 中,受控组件和非受控组件的主要区别在于数据的管理方式。受控组件的表单元素的值由 React 的 state 管理,而非受控组件的表单元素则通过 DOM 本身进行管理。受控组件的优势在于可以更好地控制用户输入并进行实时验证和处理,而非受控组件则在某些情况下提供了更简洁的代码和更少的 React 状态更新。

受控组件

受控组件 是指 React 组件通过 state 来管理表单元素的值。在这种情况下,表单元素的 value 属性由 React 的 state 控制,而不是由 DOM 自己管理。当用户输入时,表单的值会触发 onChange 事件,React 通过该事件更新组件的 state,进而改变输入框的值。每当组件的 state 发生变化时,表单的显示内容也会自动更新,确保组件的 state 和表单元素的值始终保持一致。

如下例子所示:

jsx 复制代码
import React, { useState } from "react";

function ControlledComponent() {
  const [value, setValue] = useState(""); // 管理输入框的值

  const handleChange = (event) => {
    setValue(event.target.value); // 每次输入变化时更新 state
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    alert("提交的值:" + value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        输入值:
        <input
          type="text"
          value={value} // 输入框的值由 React 的 state 控制
          onChange={handleChange} // 每次输入变化更新 state
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

export default ControlledComponent;

最终输出结果如下图所示:

在这个例子中,我们展示了如何在 React 中使用受控组件来管理表单输入的值。整个组件的状态由 React 的 useState 钩子管理,而表单元素的值通过 value 属性与 state 绑定。每当用户在输入框中输入内容时,onChange 事件会触发,更新 React 组件的 state,进而反映到输入框的显示内容。

具体来说,value={value}value 和输入框的内容绑定在一起,value 来自 useState,因此每当 value 改变时,输入框的显示内容也会自动更新。同时,onChange={handleChange} 监听输入框内容的变化,并触发 handleChange 函数,接着通过 setValue 更新 state,从而使输入框内容重新渲染。

通过这种方式,所有的表单数据都保存在 React 的 state 中,可以统一管理,比如在提交时批量处理表单数据。同时,你可以根据输入值随时做出响应,比如动态校验、自动补全或格式化等操作。而由于数据保存在 state 中,开发者也可以轻松追踪和调试表单数据,从而提高了开发效率和可维护性。

非受控组件

非受控组件 是指 React 不直接管理表单元素的值,表单元素的状态由 DOM 自行控制。在这种情况下,表单元素的 value 由 DOM 自己管理,而不是由 React 通过 state 来控制。要获取表单元素的值,React 使用 ref 引用该 DOM 元素,然后直接访问它的当前值,而不需要依赖 React 的 state 来进行管理和更新。

如下代码所示:

jsx 复制代码
import React, { useRef, FormEvent } from "react";

function UncontrolledComponent() {
  const inputRef = useRef < HTMLInputElement > null; // 创建 ref 用来访问 DOM 元素

  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (inputRef.current) {
      alert("提交的值:" + inputRef.current.value); // 通过 ref 获取 DOM 元素的值
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        输入值:
        <input
          type="text"
          ref={inputRef} // 使用 ref 来引用 input 元素
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

export default UncontrolledComponent;

最终输出结果如下所示:

在上面的代码中,我们使用 useRef 创建一个 inputRef,然后通过 inputRef.current.value 来直接获取输入框的值。在非受控组件中,表单元素的值由 DOM 自行控制,而不是通过 React 的 state 进行管理和更新。

非受控组件的主要优势在于简化代码,尤其是在表单非常简单或不需要实时处理数据时,不需要为每个表单元素管理 state,使得代码更加简洁。此外,使用非受控组件还能提升性能,特别是对于复杂表单,避免了每次输入都触发 onChange 更新 state 带来的性能问题。对于快速原型开发,非受控组件也非常适合,因为它减少了不必要的代码,使得表单实现更加直观和高效。

受控组件 vs 非受控组件 对比

特性 受控组件(Controlled Component) 非受控组件(Uncontrolled Component)
值的来源 React 的 state DOM 自身控制(通过 ref
表单数据管理 由 React 完全管理 通过 ref 获取 DOM 元素的值
数据更新方式 每次输入都会触发 onChange 更新 state 直接操作 DOM,更新时获取值
使用场景 表单复杂,需要校验、联动等操作 表单简单,数据不需要实时处理
表单验证 可以非常容易地添加验证逻辑 验证和校验不方便,难以实现实时反馈
实时更新 可以根据输入值做实时处理(如校验、格式化) 无法即时获取输入值或做动态响应
代码复杂度 需要管理 state 和事件处理 代码简单,直接使用 ref 来获取值
性能考虑 输入变化会触发多次更新(可能导致性能问题) 性能较好,避免了不必要的 state 更新

什么时候选择受控组件,什么时候选择非受控组件?

  1. 选择受控组件:

当你需要实时校验输入(比如字符限制、格式检查、必填项等),或者需要表单的值同步到 React 状态以便在其他部分使用时,受控组件是理想的选择。它还适合需要管理表单提交、批量操作表单数据的场景,例如处理选择框、按钮状态等动态交互。如果你希望通过 React 来"控制"整个表单的数据流,受控组件能够提供灵活的状态管理和数据处理。

  1. 选择非受控组件:

非受控组件适用于表单非常简单且没有复杂逻辑的情况,例如只有一个或两个输入字段,且不需要进行复杂的验证。它也适合只需要提交数据,而不需要实时响应用户输入或管理每个表单字段的场景。如果性能是关键,并且你不需要 React 完全控制表单的每个状态,非受控组件可以避免频繁的状态更新,提高性能。

总结

受控组件提供了更高的灵活性和控制,适合处理复杂的表单以及需要与 React 的 state 紧密配合的场景。通过受控组件,表单数据与 React 的状态始终保持同步,可以轻松实现验证、动态交互和状态管理。

非受控组件则更适合简单的表单,或者当你希望减少 React 对 DOM 的管理时使用。在这种情况下,通过 ref 可以直接访问 DOM 元素的值,简化代码,避免 React 对表单状态的频繁更新。

总的来说,受控组件是 React 中的标准方式,适用于大多数需要更细粒度控制的情况,而非受控组件则是当你不需要 React 完全管理表单状态时的简便选择。

对于文件上传,非受控组件适用于简单的文件上传场景,用户只需选择文件并上传,无需管理文件状态或实时反馈。受控组件适用于需要动态管理文件信息、校验文件、或显示预览等复杂操作的场景,能够实时更新文件状态并提供交互。对于大文件上传,可以通过分片上传和进度条实现更好的用户体验。

相关推荐
明似水23 分钟前
Flutter 弹窗队列管理:支持优先级的线程安全通用弹窗队列系统
javascript·安全·flutter
小小小小宇44 分钟前
前端国际化看这一篇就够了
前端
大G哥1 小时前
PHP标签+注释+html混写+变量
android·开发语言·前端·html·php
whoarethenext1 小时前
html初识
前端·html
小小小小宇1 小时前
一个功能相对完善的前端 Emoji
前端
m0_627827521 小时前
vue中 vue.config.js反向代理
前端
Java&Develop1 小时前
onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
前端·spring boot·编辑器
白泽talk1 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师1 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
HhhDreamof_1 小时前
云贝餐饮 最新 V3 独立连锁版 全开源 多端源码 VUE 可二开
前端·vue.js·开源