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"] 必须是非受控的,或者性能要求极高且逻辑简单)时才考虑使用非受控组件。

相关推荐
ttod_qzstudio15 小时前
深入理解 Vue 3 的 h 函数:构建动态 UI 的利器
前端·vue.js
芳草萋萋鹦鹉洲哦15 小时前
【elemen/js】阻塞UI线程导致的开关卡顿如何优化
开发语言·javascript·ui
_大龄15 小时前
前端解析excel
前端·excel
1***s63215 小时前
Vue图像处理开发
javascript·vue.js·ecmascript
槁***耿16 小时前
JavaScript在Node.js中的事件发射器
开发语言·javascript·node.js
一叶茶16 小时前
移动端平板打开的三种模式。
前端·javascript
前端大卫16 小时前
一文搞懂 Webpack 分包:async、initial 与 all 的区别【附源码】
前端
U***498316 小时前
JavaScript在Node.js中的Strapi
开发语言·javascript·node.js
Want59516 小时前
HTML音乐圣诞树
前端·html
老前端的功夫16 小时前
前端浏览器缓存深度解析:从网络请求到极致性能优化
前端·javascript·网络·缓存·性能优化