欢迎光临
我们一直在努力

React非受控组件深度解析:掌握表单处理的另一种姿势

一、React非受控组件的核心概念

1.1 什么是受控组件

在 React 中,受控组件是指表单元素的值由 React 的 state 完全控制。用户每次输入都会触发 onChange 事件,React 接收事件后更新 state,再由 state 驱动 UI 重新渲染,使 input 的 value 与 state 保持同步。在这种模式下,React state 就是表单数据的"单一数据源",数据的流向始终是单向的。

受控组件的核心特征是:input 的 value 绑定到 state,onChange 回调负责更新 state。这种方式让 React 对表单数据拥有完全的控制权,便于做实时校验、格式化、条件渲染等操作。

import { useState } from 'react';
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}

1.2 什么是非受控组件

非受控组件是指表单元素的值由 DOM 自身管理,React 不通过 state 实时跟踪输入值。当需要获取表单数据时,React 通过 ref 直接访问 DOM 节点并读取其 value 属性。这种方式更接近传统 HTML 表单的处理模式:表单数据保存在 DOM 中,React 只在需要时"去取"。

非受控组件的核心特征是:不绑定 value 到 state,通过 ref 引用 DOM 节点,在提交或需要时再读取值。由于 React 不参与每次输入的状态更新,因此不会因每次按键而触发重新渲染。

import { useRef } from 'react';
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log('输入的值是:', inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} defaultValue="" />
<button type="submit">提交</button>
</form>
);
}

1.3 受控组件与非受控组件的对比

理解二者的差异有助于在实际开发中做出正确选择。以下是两种模式的核心对比:

| 对比维度 | 受控组件 | 非受控组件 |

|———|———|———–|

| 数据源 | React state | DOM |

| 值的获取 | 通过 state 读取 | 通过 ref 读取 |

| 每次输入是否重新渲染 | 是 | 否 |

| 实时校验 | 容易实现 | 较难实现 |

| 代码复杂度 | 较高 | 较低 |

| 适用场景 | 复杂表单、实时校验 | 简单表单、一次性提交 |

下面用流程图直观展示两种组件的数据流向差异:

#publish-mermaid-1785728334871-0{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785728334871-0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785728334871-0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785728334871-0 .error-icon{fill:#552222;}#publish-mermaid-1785728334871-0 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785728334871-0 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785728334871-0 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785728334871-0 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785728334871-0 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785728334871-0 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785728334871-0 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785728334871-0 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785728334871-0 .marker.cross{stroke:#333333;}#publish-mermaid-1785728334871-0 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785728334871-0 p{margin:0;}#publish-mermaid-1785728334871-0 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785728334871-0 .cluster-label text{fill:#333;}#publish-mermaid-1785728334871-0 .cluster-label span{color:#333;}#publish-mermaid-1785728334871-0 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785728334871-0 .label text,#publish-mermaid-1785728334871-0 span{fill:#333;color:#333;}#publish-mermaid-1785728334871-0 .node rect,#publish-mermaid-1785728334871-0 .node circle,#publish-mermaid-1785728334871-0 .node ellipse,#publish-mermaid-1785728334871-0 .node polygon,#publish-mermaid-1785728334871-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785728334871-0 .rough-node .label text,#publish-mermaid-1785728334871-0 .node .label text,#publish-mermaid-1785728334871-0 .image-shape .label,#publish-mermaid-1785728334871-0 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785728334871-0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785728334871-0 .rough-node .label,#publish-mermaid-1785728334871-0 .node .label,#publish-mermaid-1785728334871-0 .image-shape .label,#publish-mermaid-1785728334871-0 .icon-shape .label{text-align:center;}#publish-mermaid-1785728334871-0 .node.clickable{cursor:pointer;}#publish-mermaid-1785728334871-0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785728334871-0 .arrowheadPath{fill:#333333;}#publish-mermaid-1785728334871-0 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785728334871-0 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785728334871-0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785728334871-0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785728334871-0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785728334871-0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785728334871-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785728334871-0 .cluster text{fill:#333;}#publish-mermaid-1785728334871-0 .cluster span{color:#333;}#publish-mermaid-1785728334871-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785728334871-0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785728334871-0 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785728334871-0 .icon-shape,#publish-mermaid-1785728334871-0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785728334871-0 .icon-shape p,#publish-mermaid-1785728334871-0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785728334871-0 .icon-shape .label rect,#publish-mermaid-1785728334871-0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785728334871-0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785728334871-0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785728334871-0 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node rect,#publish-mermaid-1785728334871-0 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728334871-0 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728334871-0 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}受控组件非受控组件

用户在输入框输入

组件类型

触发 onChange 事件

调用 setState 更新 state

React 重新渲染组件

input 的 value 被 state 更新

DOM 直接更新输入值

React 不感知变化

需要时通过 ref.current.value 读取

获取最终值

从图中可以看出,受控组件的数据流形成了一个闭环:输入触发 state 更新,state 更新驱动 UI 变化;而非受控组件的数据流是单向的:DOM 自行管理值,React 只在需要时通过 ref 读取。

二、非受控组件的使用方法与应用场景

2.1 使用 useRef 创建引用

useRef 是 React Hook 中用于创建 ref 引用的 API,它返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数。在非受控组件中,我们将 ref 对象赋值给 input 的 ref 属性,React 会在组件挂载后自动将 DOM 节点赋值到 ref.current 上。

import { useRef } from 'react';
function NameForm() {
const nameRef = useRef(null);
const handleClick = () => {
alert('姓名: ' + nameRef.current.value);
};
return (
<div>
<input type="text" ref={nameRef} placeholder="请输入姓名" />
<button onClick={handleClick}>获取值</button>
</div>
);
}

使用 useRef 时需要注意:修改 ref.current 不会触发组件重新渲染,这与 setState 有本质区别。ref 更像是组件的一个"盒子",用于存放跨渲染周期需要保留的值。

2.2 设置默认值

在非受控组件中,不能使用 value 属性设置初始值(这会让 input 变成只读),而应该使用 defaultValue 属性。对于 checkbox 和 radio,使用 defaultChecked;对于 select,同样使用 defaultValue。

function DefaultValueForm() {
const inputRef = useRef(null);
return (
<form>
<input
defaultValue="默认值"
ref={inputRef}
/>
<input
type="checkbox"
defaultChecked={true}
/>
<select defaultValue="banana">
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橘子</option>
</select>
</form>
);
}

2.3 处理文件输入

文件输入是典型的必须使用非受控组件的场景。在 React 中,<input type="file" /> 始终是非受控组件,因为它的值是只读的,无法通过 state 控制。用户选择文件后,通过 ref 可以访问到 FileList 对象。

function FileInput() {
const fileRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
const files = fileRef.current.files;
if (files.length > 0) {
console.log('文件名:', files[0].name);
console.log('文件大小:', files[0].size, '字节');
console.log('文件类型:', files[0].type);
}
};
return (
<form onSubmit={handleSubmit}>
<input type="file" ref={fileRef} />
<button type="submit">上传</button>
</form>
);
}

2.4 一次性表单提交场景

当表单只在提交时才需要获取所有字段的值,而不需要实时跟踪每个字段的输入状态时,非受控组件是更好的选择。这种方式避免了为每个字段维护 state,减少了不必要的渲染和代码量。

function OneTimeForm() {
const usernameRef = useRef(null);
const emailRef = useRef(null);
const messageRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
const formData = {
username: usernameRef.current.value,
email: emailRef.current.value,
message: messageRef.current.value
};
console.log('表单数据:', formData);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>用户名: </label>
<input ref={usernameRef} />
</div>
<div>
<label>邮箱: </label>
<input type="email" ref={emailRef} />
</div>
<div>
<label>留言: </label>
<textarea ref={messageRef} />
</div>
<button type="submit">提交</button>
</form>
);
}

如果用受控组件实现同样的功能,需要为三个字段分别维护 state,每个 input 都绑定 value 和 onChange,代码量明显增加,且每次输入都会触发重新渲染。

2.5 集成非 React 代码场景

当需要将 React 与非 React 代码(如 jQuery 插件、第三方库)集成时,非受控组件可以避免 React 与外部代码对同一 DOM 节点的控制冲突。React 只负责渲染,外部库负责操作 DOM,二者各司其职。

function RichEditor() {
const editorRef = useRef(null);
useEffect(() => {
// 假设使用第三方富文本编辑器
const editor = new SomeEditor(editorRef.current);
editor.init();
return () => editor.destroy();
}, []);
return <div ref={editorRef} />;
}

2.6 性能敏感的输入场景

对于某些性能敏感的场景,如大型表单中包含大量输入框,使用受控组件会导致每次输入都触发整个表单的重新渲染。此时可以考虑使用非受控组件,避免不必要的渲染开销。

三、最佳实践与注意事项

3.1 何时选择非受控组件

在实际开发中,选择非受控组件的判断依据包括以下几点:

  • 表单只在提交时需要数据,无需实时跟踪输入值。
  • 文件上传场景。
  • 集成第三方 DOM 操作库。
  • 表单字段非常多,且不需要实时校验。
  • 需要保留浏览器原生的表单行为(如自动填充、历史记录)。
  • 下面是一个决策流程图:

    #publish-mermaid-1785728335001-1{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1785728335001-1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1785728335001-1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1785728335001-1 .error-icon{fill:#552222;}#publish-mermaid-1785728335001-1 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1785728335001-1 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1785728335001-1 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1785728335001-1 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1785728335001-1 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1785728335001-1 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1785728335001-1 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1785728335001-1 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1785728335001-1 .marker.cross{stroke:#333333;}#publish-mermaid-1785728335001-1 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1785728335001-1 p{margin:0;}#publish-mermaid-1785728335001-1 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1785728335001-1 .cluster-label text{fill:#333;}#publish-mermaid-1785728335001-1 .cluster-label span{color:#333;}#publish-mermaid-1785728335001-1 .cluster-label span p{background-color:transparent;}#publish-mermaid-1785728335001-1 .label text,#publish-mermaid-1785728335001-1 span{fill:#333;color:#333;}#publish-mermaid-1785728335001-1 .node rect,#publish-mermaid-1785728335001-1 .node circle,#publish-mermaid-1785728335001-1 .node ellipse,#publish-mermaid-1785728335001-1 .node polygon,#publish-mermaid-1785728335001-1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785728335001-1 .rough-node .label text,#publish-mermaid-1785728335001-1 .node .label text,#publish-mermaid-1785728335001-1 .image-shape .label,#publish-mermaid-1785728335001-1 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1785728335001-1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1785728335001-1 .rough-node .label,#publish-mermaid-1785728335001-1 .node .label,#publish-mermaid-1785728335001-1 .image-shape .label,#publish-mermaid-1785728335001-1 .icon-shape .label{text-align:center;}#publish-mermaid-1785728335001-1 .node.clickable{cursor:pointer;}#publish-mermaid-1785728335001-1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1785728335001-1 .arrowheadPath{fill:#333333;}#publish-mermaid-1785728335001-1 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1785728335001-1 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1785728335001-1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785728335001-1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1785728335001-1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785728335001-1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1785728335001-1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1785728335001-1 .cluster text{fill:#333;}#publish-mermaid-1785728335001-1 .cluster span{color:#333;}#publish-mermaid-1785728335001-1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1785728335001-1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1785728335001-1 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1785728335001-1 .icon-shape,#publish-mermaid-1785728335001-1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1785728335001-1 .icon-shape p,#publish-mermaid-1785728335001-1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1785728335001-1 .icon-shape .label rect,#publish-mermaid-1785728335001-1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1785728335001-1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1785728335001-1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1785728335001-1 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node rect,#publish-mermaid-1785728335001-1 [data-look=\”neo\”].cluster rect,#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728335001-1 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1785728335001-1 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}是否是否是否是否

    开始选择组件类型

    需要实时校验或格式化?

    选择受控组件

    是否为文件输入?

    必须用非受控组件

    是否只需提交时获取值?

    选择非受控组件

    是否集成第三方库?

    3.2 常见陷阱与解决方案

    在使用非受控组件时,有几个常见陷阱需要注意:

  • 误用 value 属性。如果在非受控组件中使用 value 属性而不提供 onChange,React 会发出警告,input 会变成只读。正确做法是使用 defaultValue。
  • // 错误写法
    <input value="hello" ref={inputRef} />
    // 正确写法
    <input defaultValue="hello" ref={inputRef} />

  • ref 为 null 的处理。在组件首次渲染时,ref.current 可能是 null,直接访问 .value 会报错。应在事件回调中访问,确保 DOM 已挂载。
  • 无法实时响应输入变化。由于非受控组件不跟踪每次输入,如果需要在输入时执行某些逻辑(如按钮禁用状态切换),需要改为受控组件或使用其他方案。
  • 3.3 与受控组件的混合使用

    在实际项目中,非受控组件和受控组件并非互斥关系,可以在同一个表单中混合使用。通常的做法是:对需要实时校验或联动控制的字段使用受控组件,对简单的一次性提交字段使用非受控组件。

    function MixedForm() {
    const [username, setUsername] = useState('');
    const bioRef = useRef(null);
    const handleSubmit = (e) => {
    e.preventDefault();
    console.log({
    username,
    bio: bioRef.current.value
    });
    };
    return (
    <form onSubmit={handleSubmit}>
    <input
    value={username}
    onChange={(e) => setUsername(e.target.value)}
    placeholder="用户名(受控)"
    />
    <textarea
    ref={bioRef}
    placeholder="个人简介(非受控)"
    />
    <button type="submit">提交</button>
    </form>
    );
    }

    这种混合模式既保留了受控组件的实时控制能力,又利用了非受控组件的简洁性,是实际开发中推荐的做法。

    总结来说,非受控组件是 React 表单处理的重要补充,它通过 ref 直接读取 DOM 值,避免了 state 管理的复杂性,特别适合简单表单、文件上传和第三方集成等场景。理解受控与非受控的差异,根据实际需求灵活选择,才能写出既简洁又高效的 React 代码。

    赞(0)
    未经允许不得转载:171主机测评 » React非受控组件深度解析:掌握表单处理的另一种姿势
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址