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

709 阅读7分钟

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

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

受控组件

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

如下例子所示:

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;

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

20250427155201

在这个例子中,我们展示了如何在 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 来进行管理和更新。

如下代码所示:

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;

最终输出结果如下所示:

20250427160749

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

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

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

特性受控组件(Controlled Component)非受控组件(Uncontrolled Component)
值的来源React 的 stateDOM 自身控制(通过 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 完全管理表单状态时的简便选择。

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