上节课我们学习了非受控组件,当然,有非受控,那肯定就有受控,这节课,我们就来学习一下什么叫做受控组件

回顾

在学习受控组件之前,我们来对上节课做一个简单的回顾

  • form表单可以用onSubmit事件来代替给提交按钮加onClick事件
  • form表单的onSubmit事件的回调方法中可以通过event来禁用默认提交事件
  • 禁用了form表单的默认提交事件后可以通过ajax来完成与后台的交互
  • 现用现取则是非受控

以上便是上节课我们所学内容,接下来我们来开始新的内容的学习

受控组件

上节课我们说了现用现取叫非受控组件,可能大家不理解,这种现用现取这不是很正常的逻辑吗?难道还有什么是提前取好的,等着你来用还是说有其他的吗?

那我们来看看呗:

class Login extends React.Component {
  notify = e => {e.preventDefault();}
  render() {
    return (
      <form onSubmit={this.notify}>
        Username: <input type="text" name="username" />
        Password: <input type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}
ReactDOM.render(<Login />, document.getElementById("test"));

我们先看看代码,几乎和上节课是一样的代码,但是input标签没有了ref,既然没有了ref那么notify方法中也不能像上节课那样取值了。那么我们接下来该怎么处理?

我不知道大家还记不记得有个原生的方法叫onchange,只要是输入类的DOM都可以绑定onchange事件。从字面上看大家也能明白,只要输入值有变化就会触发事件。那么在react中肯定有一个onChange与之对应啊。那我们先测试一下onChange:

class Login extends React.Component {
  notify = e => {...}
  change = () => {console.log("@");};
  render() {
    return (
      <form onSubmit={this.notify}>
        Username: <input onChange={this.change} type="text" name="username" />
        Password: <input type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}

我们先给用户名的input标签添加了onChange事件。那么我们想一下,只要我们在用户名的input栏里面是不是只要一输入或者一删除就会在控制台中打印出@?那我们来看一下效果:

image-20211228134742298

我输入了 7 个数字,然后在控制台中就打印了 7 次@。我们目前是随着我们的输入,我们指定的回调方法就不断呗调用,那我们能不能随着输入就拿到输入的值呢?当然是可以的。

我们来分析一下:

  1. 是不是给input绑定的onChange
  2. 是不是要拿到这个input的值?

那么直接借助event.target就可以了啊,我们吧代码改一下:

class Login extends React.Component {
  notify = e => {...};
  change = e => {console.log(e.target.value);};
  render() {
    return (
      <form onSubmit={this.notify}>
        Username: <input onChange={this.change} type="text" name="username" />
        Password: <input type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}

我们在change方法中直接通过event来获取到了input这个DOM节点的值,那么我们看看打印出来是不是如我们预期一样:

image-20211228135644345

如我们所见,我们在input栏只要有变化,那么控制台就会打印出当前一次变化之后的值。

那么我们现在拿到值了。我们怎么用啊?我光拿到了不行啊。那我们怎么办呢?我们可以存到state里面啊。那我们把代码这么一改:

class Login extends React.Component {
  notify = e => {...};
  change = e => {this.setState({ username: e.target.value });};
  render() {
    return (
      <form onSubmit={this.notify}>
        Username: <input onChange={this.change} type="text" name="username" />
        Password: <input type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}

这样的话我每修改一下用户名的input栏,是不是都会把input DOM节点的值哇偶维护进了state里面?可能有人要说了,我怎么就知道有没有维护到state里呢?那我们来看一下呗:

image-20211228140746833

我们在还没有输入任何值的时候,我们看一下啊,为什么没有state?因为我们根本没有在代码里来做初始化。那么我们输入一下试试:

image-20211228140605950

在我们的react的开发工具中可以很直观得看到我们的state拿到值了。但是这么做其实是不规范的。连初始化都没做就直接往里面放东西这种做法很明显不规范。那我们就初始化一下呗:

class Login extends React.Component {
  state = {
    username: "",
    password: ""
  }
  notify = e => {...}
  change = e => {...};
  render() {return ...}
}

所以说这一步我们最好在使用前来初始化一下。那么同理给passwordinput也同样加一个onChange,并把输入的内容存放在state中这一步我们是不是已经去到了输入的值了?但是我们用了吗?是不是我们只是取到了并且存储到了state里了但是我们其实并没有拿来用。那么form表单的onSubmit事件的回调就好写了啊:

class Login extends React.Component {
  state = {
    username: "",
    password: ""
  }

  notify = e => {
    e.preventDefault();
    const { username, password } = this.state;
    alert(`{username}: {password}`);
  }

  change = e => { this.setState({ username: e.target.value }); };
  change1 = e => { this.setState({ password: e.target.value }); };

  render() {
    return (
      <form onSubmit={this.notify}>
        Username: <input onChange={this.change} type="text" name="username" />
        Password: <input onChange={this.change1} type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}

我们来看一下完整代码,初始化staterender方法中返回一个form表单,form表单绑定onSubmit事件,该事件的回调方法是notify方法。input标签利用onChange事件将输入的值存入state,当点击提交按钮时触发form表单的onSubmit事件的回调方法,该方法用参数e接收event,并且用preventDefault方法来禁止默认提交事件,然后从state拿到usernamepassword解构赋值,然后再弹窗展示出来。那么我们来看看具体是什么效果:

image-20211228142548452

图中可以很直观德看出我们输入用户名和密码之后,点击提交按钮成功展示了相关信息,而且state中也存储了我们输入的值。

所以说我们得出了这么一个结论。上面这种所有输入类的DOM随着输入就可以将输入的值存入state,等需要使用时直接从state中取出来就属于受控组件。

所以我们对比非受控组件,差异就太明显了。因为非受控组件不经过state啊,现用现取,在我们的案例中通过refs去取,而受控组件则是在输入过程中就已经在取值并且维护到了state中了。

那有人要问了,那我以后开发的时候是写受控组件还是非受控组件啊?其实我们是建议写受控组件的。我们在受控组件中是不是一个ref都没用啊?官方给的建议就是尽量减少ref的使用。那么我们受控组件的优势就出来了。

总结

  • 受控组件在输入过程中就开始取值
  • 受控组件把输入的值维护到state
  • 受控组件可以减少ref的使用

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/controled_component/