React当中受控组件与非受控组件的区别

在 React 中,受控组件 (Controlled Components)非受控组件 (Uncontrolled Components) 是两种管理表单数据的方式,主要区别在于表单数据由谁来管理(状态来源)以及如何获取用户输入的值

1. 受控组件 (Controlled Components)

核心思想: 表单元素的值(value)由 React 组件的 state 管理。React 完全控制表单元素的状态。

实现方式:

  • 将表单元素(如 <input>, <textarea>, <select>)的 value 属性绑定到组件的 state
  • 通过 onChange 事件处理函数监听用户的输入,并在该函数中更新 state
  • 由于 valuestate 控制,任何输入都会先触发 onChange,更新 state,然后 state 的变化会重新渲染组件,从而更新 value,形成一个闭环。

优点:

  • 数据流清晰: 所有表单数据都集中管理在 React 的 state 中,便于调试和维护。
  • 易于验证和转换: 可以在 onChange 处理函数中轻松地对输入进行实时验证、格式化或转换。
  • 易于重置或预填充: 只需修改 state,表单值就会随之改变。
  • 符合 React 单向数据流原则。

缺点:

  • 代码量稍多: 需要为每个需要控制的表单元素编写 stateonChange 处理函数。
  • 性能开销: 每次输入都触发 state 更新和组件重新渲染(虽然 React 通常能优化得很好)。

示例:

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

function ControlledInput() {
  const [name, setName] = useState('');

  const handleChange = (event) => {
    setName(event.target.value); // 更新 state
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('提交的姓名:', name);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        姓名:
        <input
          type="text"
          value={name} // value 由 state 控制
          onChange={handleChange} // 通过事件更新 state
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

2. 非受控组件 (Uncontrolled Components)

核心思想: 表单元素的值由元素自身(DOM)管理,而不是由 React 的 state 管理。React 不直接控制其值。

实现方式:

  • 使用 ref 通过 useRef Hook 或 createRef() 创建一个 ref,并将其附加到表单元素上。
  • 获取值: 当需要获取表单数据时(例如在提交时),通过 ref.current 访问 DOM 元素,然后读取其 value 属性。
  • 默认值: 可以使用 defaultValue(或 defaultChecked 等)属性来设置初始值,之后这个值就由 DOM 自己管理了。

优点:

  • 更接近原生 HTML: 对于简单的表单或需要与非 React 代码集成时,使用起来更直接。
  • 减少代码量: 对于不需要实时响应输入的场景,代码更简洁。
  • 性能: 避免了频繁的 state 更新和重新渲染(仅在需要时读取值)。

缺点:

  • 数据流不清晰: 表单数据分散在 DOM 中,不如 state 集中管理。
  • 难以实时验证/转换: 无法像受控组件那样在 onChange 中轻松处理。
  • 难以动态控制: 从 React 代码中改变非受控组件的值比较麻烦(需要操作 ref)。
  • 与 React 哲学不完全一致: 将状态管理交给了 DOM。

示例:

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

function UncontrolledInput() {
  const nameInputRef = useRef(null); // 创建 ref

  const handleSubmit = (event) => {
    event.preventDefault();
    // 通过 ref 获取 DOM 元素的值
    console.log('提交的姓名:', nameInputRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        姓名:
        <input
          type="text"
          ref={nameInputRef} // 将 ref 附加到 input
          defaultValue="初始值" // 设置默认值(只在首次渲染时有效)
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

总结对比表

特性 受控组件 (Controlled) 非受控组件 (Uncontrolled)
状态管理 React state DOM 自身
值来源 value 属性绑定到 state 通过 ref 读取 DOM 的 value
初始值 state 的初始值 defaultValue 属性
获取值时机 任何时刻(通过 state 提交或需要时(通过 ref
实时响应 容易(onChange 困难
数据流 清晰,单向(React) 分散(DOM)
代码复杂度 相对较高(需 stateonChange 相对较低
适用场景 需要实时验证、格式化、动态控制、复杂表单逻辑 简单表单、文件上传、集成非 React 代码、性能敏感且无需实时控制的场景

一般建议: 在大多数情况下,优先使用受控组件 ,因为它更符合 React 的设计理念,数据流更清晰,功能更强大。只有在特定需求(如处理文件输入 input[type="file"] 必须是非受控的,或者性能要求极高且逻辑简单)时才考虑使用非受控组件。

相关推荐
传奇开心果编程6 分钟前
【传奇开心果系列】Flet框架实现的图形化界面的PDF转word转换器办公小工具自定义模板
前端·python·学习·ui·前端框架·pdf·word
IT_陈寒42 分钟前
Python开发者必知的5个高效技巧,让你的代码速度提升50%!
前端·人工智能·后端
zm4351 小时前
浅记Monaco-editor 初体验
前端
超凌1 小时前
vue element-ui 对表格的单元格边框加粗
前端
渊不语1 小时前
PasteTextArea 智能文本域粘贴组件 - 完整实现指南
react.js
前端搬运侠1 小时前
🚀 TypeScript 中的 10 个隐藏技巧,让你的代码更优雅!
前端·typescript
CodeTransfer1 小时前
css中animation与js的绑定原来还能这样玩。。。
前端·javascript
liming4951 小时前
运行node18报错
前端
20261 小时前
14.7 企业级脚手架-制品仓库发布使用
前端·vue.js