面试题:什么是 React 受控组件和非受控组件?它们有什么区别?

在 React 中,组件可以分为受控组件 (Controlled Components)非受控组件 (Uncontrolled Components)。这种分类主要针对处理表单元素(如 <input>, <textarea>, <select>)数据的方式。

1. 受控组件 (Controlled Components)

定义
受控组件是指其值由 React 组件的状态 (state) 控制的表单元素。表单元素的当前值通过 value (或 checked 等) 属性从 React 的 state 中获取,并且任何用户输入都通过事件处理器(如 onChange)来更新 state,从而形成一个单向数据流。

特点

  • 数据来源单一:表单数据的唯一来源是 React 组件的 state
  • React 完全控制:React 负责渲染表单的当前值和响应用户的输入。
  • 实时同步:用户输入时,state 会立即更新,UI 也随之更新。

示例

import React, { useState } from 'react';

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

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

  const handleSubmit = (event) => {
    event.preventDefault();
    alert('提交的名字: ' + name);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        名字:
        {/* value 由 state 控制,onChange 更新 state */}
        <input type="text" value={name} onChange={handleChange} />
      </label>
      <input type="submit" value="提交" />
    </form>
  );
}

在这个例子中,<input>value 始终等于 name 这个 state。用户输入时,handleChange 会更新 name,然后 React 重新渲染,输入框显示新的值。React 完全“控制”了这个输入框。

2. 非受控组件 (Uncontrolled Components)

定义
非受控组件是指其值由 DOM 自身管理的表单元素。组件的初始值可能通过 defaultValuedefaultChecked 设置,但之后的值变化由浏览器 DOM 自行处理,而不是通过 React 的 state

特点

  • 数据来源是 DOM:表单数据的来源是真实的 DOM 节点。
  • DOM 控制:表单元素自己维护其状态。
  • 需要 Refs 访问:要读取或修改表单的值,必须使用 ref 来直接操作 DOM 节点。

示例

import React, { useRef } from 'react';

function NameForm() {
  const inputRef = useRef();

  const handleSubmit = (event) => {
    event.preventDefault();
    // 通过 ref 访问 DOM 节点的值
    alert('提交的名字: ' + inputRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        名字:
        {/* 使用 ref 引用 DOM 节点,defaultValue 只设置初始值 */}
        <input type="text" defaultValue="初始值" ref={inputRef} />
      </label>
      <input type="submit" value="提交" />
    </form>
  );
}

在这个例子中,<input> 的值由浏览器 DOM 管理。React 不跟踪输入框的当前值。只有在提交时,通过 inputRef.current.value 才能从 DOM 中读取到最新的值。

主要区别

特性受控组件 (Controlled)非受控组件 (Uncontrolled)
数据存储存储在 React 组件的 state存储在 DOM 节点自身中
值的控制者React 组件(通过 value 属性)浏览器 DOM
数据流单向数据流(state -> UI,事件 -> 更新 state)React 只在需要时从 DOM “拉取”数据
访问值的方式直接访问 state 变量必须使用 ref 访问 DOM 节点
实时性值与 state 实时同步值可能与 React 不同步,需要手动查询
初始值属性value(结合 onChangedefaultValue(仅初始值)
适用场景需要实时验证、动态更新、复杂表单逻辑文件输入、集成非 React 库、性能敏感且不需频繁读取的场景

选择建议

  • 优先使用受控组件:这是 React 推荐的模式。它使组件的行为更可预测、更易于调试,并且数据流清晰,便于实现表单验证、动态输入、条件渲染等复杂逻辑。
  • 谨慎使用非受控组件:在某些特定场景下可能更简单,例如:
    • 处理文件上传(<input type="file" />,因为其值是只读的)。
    • 集成一些不基于 React 的第三方库。
    • 性能要求极高,且不需要频繁读取表单值的简单输入。

总结:受控组件将表单数据的“控制权”交给 React 的 state,而非受控组件则让 DOM 自己管理数据。现代 React 开发中,受控组件是标准做法,而非受控组件是一种补充手段。

THE END
喜欢就支持一下吧
点赞13 分享