react 受控组件和非受控组件

118 阅读3分钟

受控组件基本概念

通过名称,我们可以猜测一下这两个词是什么意思:

  • 受控组件:受我们控制的组件
  • 非控组件:不受我们控制的组件

咳咳,好吧,这里的受控和非控是什么意思呢?其实也就是我们对某个组件状态的掌控,它的值是否只能由用户设置,而不能通过代码控制

我们知道,在React中定义了一个input输入框的话,它并没有类似于Vuev-model的这种双向绑定功能。也就是说,我们并没有一个指令能够将数据和输入框结合起来,用户在输入框中输入内容,然后数据同步更新。

就像下面这个案例:

jsx
复制代码
class TestComponent extends React.Component {
  render () {
    return <input name="username" />
  }
}

用户在界面上的输入框输入内容时,它是自己维护了一个"state",这样的话就能根据用户的输入自己进行UI上的更新。(这个state并不是我们平常看见的this.state,而是每个表单元素上抽象的state)

想想此时如果我们想要控制输入框的内容可以怎样做呢?唔...输入框的内容取决的是input中的value属性,那么我们可以在this.state中定义一个名为username的属性,并将input上的value指定为这个属性:

jsx
复制代码
class TestComponent extends React.Component {
  constructor (props) {
    super(props);
    this.state = { username: 'lindaidai' };
  }
  render () {
    return <input name="username" value={this.state.username} />
  }
}

但是这时候你会发现input的内容是只读的,因为value会被我们的this.state.username所控制,当用户输入新的内容时,this.state.username并不会自动更新,这样的话input内的内容也就不会变了。

哈哈,你可能已经想到了,我们可以用一个onChange事件来监听输入内容的改变并使用setState更新this.state.username

jsx
复制代码
class TestComponent extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      username: "lindaidai"
    }
  }
  onChange (e) {
    console.log(e.target.value);
    this.setState({
      username: e.target.value
    })
  }
  render () {
    return <input name="username" value={this.state.username} onChange={(e) => this.onChange(e)} />
  }
}

现在不论用户输入什么内容stateUI都会跟着更新了,并且我们可以在组件中的其它地方使用this.state.username来获取到input里的内容,也可以通过this.setState()来修改input里的内容。

OK👌,现在让我们来看看受控组件的定义:

在HTML的表单元素中,它们通常自己维护一套state,并随着用户的输入自己进行UI上的更新,这种行为是不被我们程序所管控的。而如果将React里的state属性和表单元素的值建立依赖关系,再通过onChange事件与setState()结合更新state属性,就能达到控制用户输入过程中表单发生的操作。被React以这种方式控制取值的表单输入元素就叫做受控组件

非受控组件

上面👆向大家展示的是受控组件的一些基本概念还有相关操作,对于受控组件,我们需要为每个状态更新(例如this.state.username)编写一个事件处理程序(例如this.setState({ username: e.target.value }))。

那么还有一种场景是:我们仅仅是想要获取某个表单元素的值,而不关心它是如何改变的。对于这种场景,我们有什么应对的方法吗🤔️?

唔...input标签它实际也是一个DOM元素,那么我们是不是可以用获取DOM元素信息的方式来获取表单元素的值呢?也就是使用ref

就像下面👇这个案例一样:

jsx
复制代码
import React, { Component } from 'react';

export class UnControll extends Component {
  constructor (props) {
    super(props);
    this.inputRef = React.createRef();
  }
  handleSubmit = (e) => {
    console.log('我们可以获得input内的值为', this.inputRef.current.value);
    e.preventDefault();
  }
  render () {
    return (
      <form onSubmit={e => this.handleSubmit(e)}>
        <input defaultValue="lindaidai" ref={this.inputRef} />
        <input type="submit" value="提交" />
      </form>
    )
  }
}

在输入框输入内容后,点击提交按钮,我们可以通过this.inputRef成功拿到inputDOM属性信息,包括用户输入的值,这样我们就不需要像受控组件一样,单独的为每个表单元素维护一个状态。

同时我们也可以用defaultValue属性来指定表单元素的默认值。

转自 juejin.cn/post/685827…