jtwang7 / React-Note

React 学习笔记
8 stars 2 forks source link

受控组件 & 非受控组件 #35

Open jtwang7 opened 2 years ago

jtwang7 commented 2 years ago

参考文章: React受控组件和非受控组件

前言

官方定义: 受控组件 非受控组件

React 的受控组件与非受控组件的概念是相对于表单而言的。 在 React 中,表单元素通常会持有一个内部的 state,因此,它的工作方式与其他HTML元素不一样,而获取表单元素内部 state 的实现方式的不同,就产生了受控组件和非受控组件

受控组件

HTML 的表单元素(如input、textarea、select等) 在其内部实现了对输入值的存储和维护,这个内部维护的方法逻辑对外是不可见的,输入值只能通过取值的方式获得。

也就是说,我们对表单元素输入的信息,是由 HTML 元素自身内部机制所控制的,这对于开发者而言,意味着输入信息是不可控的。

为了让表单输入数据是受开发者控制的,我们就需要抛开元素标签内部的实现,手动保存一个变量,存储输入数据,并定义相应的方法响应数据的更新。 在 React 中,我们利用 state 状态变量来存储表单输入数据:state 将输入值传入表单内部,作为默认值,待表单内部有修改时,会通过 setState 同步更新外部的 state 变量。可以看到,我们将原来表单内部自身维护的变量通过 state 的方式暴露出来,而 state 的传递和更新现在都受我们自己控制了,这就是状态受控的表现。

handleChange(event) {  this.setState({value: event.target.value}) }

// 表单(受控)
<input type="text" value={this.state.value} onChange={this.handleChange} />

非受控组件

其实通过对受控组件的了解,你就能大致区分什么是受控组件,什么是非受控组件了。 原生的 HTML 表单元素,实际上就可以被理解为是非受控组件,因为它的状态(输入数据等)是由内部机制维护的,是元素标签自身就定义好的。 对于非受控组件而言,我们只能直接操纵它的 DOM 节点才能获取到它内部的值。React 中通过 ref 对象获取 DOM 引用实现。

this.inputValue = React.createRef();

// 表单(非受控)
<input type="text" ref={this.inputValue} />
// this.inputValue.value 获取输入数据

总结

判断一个组件是不是受控组件: 从本质上分析,就要看这个表单组件它的状态是否是可掌控的,以 React 实现为例: 受控组件:状态由 react 的 state 状态维护,它的值保存在 this.state 中,并能使用 setState 将修改后的值同步到 state。 非受控组件:状态由元素自身内部维护,值保存在元素内部,数据的更新同步也是默认定义好并由内部机制完成的,外界无法对其做任何自定义的修改。外部使用非受控组件只能通过操纵其 DOM 节点来获取值。

从方法上分析: 表单数据状态受 React 的 state 控制,通过 setState 修改的就是受控组件,通过 DOM 控制,不受 state 控制的就是非受控组件。

jtwang7 commented 1 year ago

受控与非受控的决策

受控组件没有内部状态或内部状态完全由 props 决定的组件 非受控组件存在不受 props 控制的内部状态的组件

受控和非受控常见于与用户交互相关的组件中,典型的例子是原生的 input 组件,根据不同写法,可以是受控也可以是非受控

/* 受控的 input 写法 */
<input value={text} onChange={handleChange} />

/* 非受控 input 写法 */
<input defaultValue={initialText} onChange={handleChange} />

React 社区已经形成一种共识,如果一个组件既可以受控也可以非受控运行,一般传入 defaultValue/defaultChecked 的表示运行在非受控模式,传入 value/checked 和 onChange 表示运行在受控模式。

受控组件的优缺点

优点:

缺点:

特点: value/checked 和 onChange 成对出现(也可以使用事件代理在父元素上冒泡处理所有 onChange 事件,但 React 对于受控组件的判断是 value/checked 和 onChange 成对出现,不然会在 development 模式下有个 warning)。受控组件需要在 onChange 的时候更改 state,来触发重绘。

非受控组件优缺点

优点:

缺点:

特点: 只有一个 defaultValue/defaultChecked 的属性。不需要更新记录 state,因此也不会造成重绘。实现功能的代码也更少。但对于复杂的联动需求(关联交验、联动更新)的场景,难以支持(或者说需要额外的技巧)。所以大多数没有性能瓶颈的情况下,推荐大家使用受控组件开发。