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

相关推荐
WooaiJava1 小时前
AI 智能助手项目面试技术要点总结(前端部分)
javascript·大模型·html5
LYFlied1 小时前
从 Vue 到 React,再到 React Native:资深前端开发者的平滑过渡指南
vue.js·react native·react.js
爱喝白开水a1 小时前
前端AI自动化测试:brower-use调研让大模型帮你做网页交互与测试
前端·人工智能·大模型·prompt·交互·agent·rag
Never_Satisfied1 小时前
在JavaScript / HTML中,关于querySelectorAll方法
开发语言·javascript·html
董世昌411 小时前
深度解析ES6 Set与Map:相同点、核心差异及实战选型
前端·javascript·es6
WeiXiao_Hyy2 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡2 小时前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone2 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09013 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农3 小时前
Vue 2.3
前端·javascript·vue.js