受控与非受控
随缘更新...随缘拓展...
在 React 当中有一对相对组件概念:受控组件和非受控组件。官方推荐我们使用受控组件,而不是非受控组价。
React 中什么是受控组件[1]
很多初学React不明白受控组件和非受控组件[2]有什么区别。其实一句话就明白了:开发人员要组件要控制什么?
当然是 state, 也就是数据了。我们知道 React 当中 state 在数据展示和更新中扮演重要的角色。React 是通过 state 和 state 的变化 来控制视图层数据的展示和更新任务。所以控制其实是通过 state 来控制 React 程序。从源码的层面,组件数据更新都是通过调用 Component.prototype.update/forceUpdate[3] 来更新 state,从而控制程序的。
受控组件实例
一个简单的受控组件的例子。
我们所写的 React 组件一般都是都是受控组件(就好比"道"长存于心,但不知"道"), 以下 state.a 的定义和更新的过程就是在 React 的控制范围内,因此 Article 组件即受控组件。
import React, { Component } from 'react'
class Article extends Component {
state = {
a: 1
}
handleChange() {
this.state += 1
}
render() {
let { a } = this.state
return (
<>
<div>{a}</div>
<button onClick={this.handleChange.bind(this)}>点我state + 1</button>
</>
)
}
}
非受控组件实例
React 实际使用了虚拟 DOM 来节省了 DOM 的消耗,但是真的我们就不在需要直接操作DOM了吗?
答案是否定的。
因为我们在 Raect 当中难免会引入第三方库(DOM库),难免有触发动画等等需要操作DOM。也就是说声明式的操作 DOM 是避免不了的。React ref[2:1] 就提供了触碰 DOM 的能力,在构建非受控组件起到很大的作用, 下面是官方的对比的例子:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 创建一个 ref 来存储 textInput 的 DOM 元素
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 直接使用原生 API 使 text 输入框获得焦点
// 注意:我们通过 "current" 来访问 DOM 节点
this.textInput.current.focus();
}
render() {
// 告诉 React 我们想把 <input> ref 关联到
// 构造器里创建的 `textInput` 上
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
何时使用受控组件
- React 当中推荐使用受控组件, React hooks 出来之后,更加推荐使用 hooks 的
函数式受控组件。
何时使用非受控组件
- 需要处理
与 DOM 相关的操作时,一般配合Ref来获取 DOM。