React
的受控组件与非受控组件的概念是相对于表单而言的,在React
中表单元素通常会持有一下内部的state
,因此它的工作方式与其他HTML
元素不一样,而获取表单元素内部state
的实现方式的不同,就产生了受控组件和非受控组件。
在HTML
的表单元素中,它们通常自己维护一套state
,并随着用户的输入自己进行UI
上的更新,这种行为是不被我们程序所管控的,而如果将React
里的state
属性和表单元素的值建立依赖关系,再通过onChange
事件与setState()
结合更新state
属性,就能达到控制用户输入过程中表单发生的操作,React
以这种方式控制取值的表单输入元素就叫做受控组件。
在React
中定义了一个input
输入框的话,它并没有类似于Vue
里v-model
的这种双向绑定功能,也就是说我们并没有一个指令能够将数据和输入框结合起来,用户在输入框中输入内容,然后数据同步更新。
- class Input extends React.Component {
- render () {
- return "username" />
- }
- }
用户在界面上的输入框输入内容时,它是自己维护了一个state
,这个state
并不是我们平常看见的this.state
,而是每个表单元素上抽象的state
,这样的话就能根据用户的输入自己进行UI
上的更新,如果我们想要控制输入框的内容,而输入框的内容取决的是input
中的value
属性,那么我们可以在this.state
中定义一个名为username
的属性,并将input
上的value
指定为这个属性。
- class Input extends React.Component {
- constructor (props) {
- super(props);
- this.state = { username: "1" };
- }
- render () {
- return "username" value={this.state.username} />
- }
- }
但是这时候你会发现input
的内容是只读的,因为value
会被我们的this.state.username
所控制,当用户输入新的内容时,this.state.username
并不会自动更新,这样的话input
内的内容也就不会变了,此时控制台通常会抛出一个Warning
。
Warning: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
您为表单字段提供了一个没有onChange
处理程序的value
属性,这将呈现只读字段,如果字段应该是可变的,请使用defaultValue
,否则请设置onChange
或readOnly
。
这段Warning
其实给出了对于这个问题的解决方案,我们只需要对组件的onChange
事件来监听输入内容的改变并使用setState
更新this.state.username
即可,如此我们在当前组件中能够控制这个表单元素的值,这就是受控组件。
- class Input extends React.Component {
- constructor (props) {
- super(props);
- this.state = { username: "1" };
- }
- render () {
- return (
- <>
- "username" value={this.state.username}
- onChange={e => this.setState({username: e.target.value})}
- />
-
- >
- )
- }
- }
此外需要注意的是,如果是讲此组件作为一个共用的组件用以调用的话,是有弊端的,尽管此时Input
组件本身是一个受控组件,但与之相对的调用方失去了更改Input
组件值的控制权,所以对调用方而言,Input
组件是一个非受控组件,以非受控组件的使用方式去调用受控组件是一种反模式,下边的例子都是属于Hooks
的写法。
- // 组件提供方
- function Input({ defaultValue }) {
- const [value, setValue] = React.useState(defaultValue)
- return setValue(e.target.value)} />
- }
-
- // 调用方
- function UseInput() {
- return
- }
如果要对于组件提供方还是调用方Input
组件都为受控组件,只需要提供方让出控制权即可。
- // 组件提供方
- function Input({ value, onChange }) {
- return
- }
-
- // 调用方
- function UseInput() {
- const [value, setValue] = React.useState(1);
- return setValue(e.target.value)} />
- }
如果表单元素并不经过state
,而是通过ref
修改或者直接操作DOM
,那么它的数据无法通过state
控制,这就是非受控组件。
- class Input extends React.Component {
- constructor (props) {
- super(props);
- this.input = React.createRef();
- }
- render () {
- return (
- <>
- "username" ref={this.input} />
-
- >
- )
- }
- }
state
中。value
或checked prop
相对应。react
受控组件更新state
的流程:
state
中设置表单的默认值。onChange
事件处理器。event
拿到改变后的状态,并更新应用的state
。SetState
触发视图的重新渲染,完成表单组件值的更新。value prop
就可以称为非受控组件。state
或props
控制。ref prop
来访问渲染后的底层DOM
元素。defaultValue
指定value
值。