上节课我们学习了关于react的事件处理,说了关于ref是否可以省略。这节课我们将开始进入下一课的学习,非受控组件。

回顾

在学习非受控组件之前,我们来对上节课内容来进行简单的回顾。

  • 不要过度使用ref
  • 事件监听要严格注意大小写
  • 通过event.target获取到事件发生的DOM元素

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

收集表单数据

可能有朋友要问了,我们的大标题叫非受控组件,怎么扯到表单数据收集了呢?其实我们将通过表单数据的收集来介绍受控组件和非受控组件。

可能有人要问这个受控是啥意思?其实就是字面意思,收到控制,受到谁的控制?先不纠结咱们在学习中慢慢探讨。

案例需求

我们先来看一下我们的案例需求是什么?

  • 定义一个包含表单的组件
  • 输入用户名和密码点击登录之后提示相关信息

案例实现

我们这个需求其实很简单,就是最基本的用户登录操作,只不过我们把登录那一步去掉了,换成了展示信息。

实现页面基本结构

那我们先不要那么着急,一步一步来,先把基本页面实现了:

class Login extends React.Component {
  render() {
    return (
      <form action="#">
        Username: <input type="text" />
        Password: <input type="password" />
        <button>Submit</button>
      </form>
    );
  }
}
ReactDOM.render(<Login />, document.getElementById("test"));

我们来看一下这段代码,很简单的几个步骤:

  1. 创建组件
  2. 编写render方法
  3. 返回一个form表单
  4. 编写页面基本元素
  5. 渲染组件

我们来看一下结果:

image-20211228095705400

这样页面的基本结构算是完成了也可以输入用户名和密码,而且密码也是密文。

点击按钮触发结果

大家想一想现在submit按钮起作用吗?我们还没有加点击事件。但是我们先不考虑按钮的点击事件,我们就先思考一下如果我们点击了会怎么样呢?

大家注意看一下我们的form标签。form标签里面是不是有一个action属性?这个属性是干什么的大家应该都清楚,就是点击提交按钮之后我们表单往那提交呢,其实就是往我们action属性的链接里面提交。那我们把action属性设定成了#看一下点击前和点击后的效果:

image-20211228101200377

所以大家看见了,这其实是页面跳转了。即便我没有给submit按钮添加onClick事件,但是点击按钮还是出现了页面出现跳转的情况。可能大家看着还是不够直观。我们把action属性改一下<form action="https://www.baidu.com">我们把链接改成了百度,那么这次点击是不是就会跳转到百度呢?

image-20211228102027995

我们来看,点击按钮之后确实跳转到了百度,但是url后面是不是还有一个问号啊?这个问号是什么意思呢?

form表单信息

我们之前说过表单信息是要提交给action属性中的链接的,如果我们没有指定请求方式,那么我们form表单发出的是不是GET请求?GET请求的参数会体现在url上,并通过问号来将参数列表和url链接进行隔开。而form表单发出GET请求带的参数是query参数。但是呢我们从url上面来看,只有一个问号,问号后面的参数呢?

我们再回头看代码,我们的input标签是不是只有type标签?而且我们也知道form表单提交出去的参数肯定就是这里input栏输入的数据,但是form表单知道这两个input中输入的值分别都是什么吗?不知道啊,所以说input标签我们需要给他们加上name属性,这样form表单才知道这两个input栏输入的参数名称分别是什么,那我们改一下代码再看看效果

class Login extends React.Component {
  render() {
    return (
      <form action="https://www.baidu.com">
        Username: <input type="text" name="username" />
        Password: <input type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}

看看这次的效果是什么样子:

image-20211228103230531

这次跳转到了百度,而且参数也带上了。

但是我们要做的是跳转到百度吗?当然不是,我们是想弹窗提示用户登录成功啊。那我们怎么办?可能有朋友要说,那我给按钮绑定一个onClick事件,然后通过refs来做不就得了。当然这种做法 OK 的,没毛病,天王老子来了都不能说你这个做法是错的。但是那样做的话,我们还写表单干什么啊?

form表单事件

那么如果我们不用这种方法还有什么方法可以用呢?我们来回想一下form标签是不是有一个原生的onsubmit属性?那么在react中的话呢?回忆一下之前说过的是不是就有一个对应的onSubmit?那么是不是就简单很多了?给一个回调呗:

class Login extends React.Component {
  notify = () => {}
  render() {return <form action="https://www.baidu.com" onSubmit={this.notify}>...</form>}
}

那么好,我们来分析一下上面这段代码,我们给表单加了onSubmit事件绑定,要求表单在提交时直接执行我们给的回调。那么这个回调函数我们得定义啊。赋值语句加箭头函数来定义这个回调函数。好,这个回调函数这么写?

分析一下:

  1. 我们是不是要展示input栏输入的信息?
  2. onSubmit是不是加给form标签的?

那么这样的话我们能用event.target来获取吗?肯定不能啊,那么我们就得给这两个input标签添加ref了啊,那我们再来改一下代码:

class Login extends React.Component {
  notify = () => { 
    const {username, password} = this;
    alert(`{username.value}: {password.value}`);
  }

  render() {
    return (
      <form action="https://www.baidu.com" onSubmit={this.notify}>
        Username: <input ref={c => this.username = c} type="text" name="username" />
        Password: <input ref={c => this.password = c} type="password" name="password" />
        <button>Submit</button>
      </form>
    );
  }
}

现在我们来看:我们用回调函数的形式给两个input标签都加上了ref,那么notify回调函数是不是就好写了?你看我们这两个ref分别在this上加了usernamepassword属性,而且这两个属性还分别就是这两个input标签的DOM节点,但是我们想要展示值,那么是不是该取value属性?所以说notify方法中第一步先结构赋值,然后展示这两个节点的value。那么我们来看一下啊结果:

image-20211228111114436

这下我们可以成功展示出form表单中的信息了,但是这个弹窗提醒我们点了确定之后就有问题了:

image-20211228111347803

又跳转到百度了。可能有朋友要说,这有啥问题啊?表单提交嘛,本来就是往这提交的啊。但是我们的需求是什么啊?我们就想提示信息,我们并不想真正地提交,不想让页面跳转出去,我们不想让页面刷新。或许有朋友要说,那你不写action属性不就行了嘛。那我们来试试。

image-20211228112045930

大家觉得什么叫做页面没有刷新?是不是没有触发刷新按钮?而且url也没有任何变化,这种才是页面没有刷新?这两个条件缺一不可。那么我们看一下图里。url变了,如果我这边是个视频的话,大家会看见刷新按钮是被触发过一次的。所以说不给action属性其实没有用。

但是表单提交是表单默认动作,我们怎么禁止这种动作呢?其实表单是有原生的阻止默认事件的方法的。那么我们再来修改一下:

class Login extends React.Component {
  notify = e => { 
    e.preventDefault();
   ...
  }

  render() {...}
}

我们在notifye参数接收event,然后调用eventpreventDefault方法就可以完成默认事件的禁用。我们再看一下效果:

image-20211228114051777

点击了确定之后,什么变化都没有。但是这个禁用掉了,我们怎么提交呢?这里就要提到我们曾经学到过得ajax了,当然有关ajax不是我们目前需要重点讨论的。只是先提一下。

非受控组件

其实我们至此我们就已经完成了一个非受控组件。但是这是什么意思呢?

我们来思考几个问题:

  1. 页面里面是不是有表单,而且表单中有两个输入项?
  2. 是不是我们点击Submit按钮的时候才获取到两个输入项的值?

那么好,我们有这样一个结论,上面页面表单中的所有输入类DOM的值,现取现用的话就是非受控组件,可能大家要说,啥叫现取现用?我们看我们上面的写法:是不是我们在notify方法中才要用到我们输入类的DOM的值?那么这个值是在什么时候获取取的?是不是在notify方法中在使用前才去通过this来获取?也就是说这种只有在需要使用输入类的DOM的值的时候才去获取的话,那么这个组件就是非受控组件。

总结

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

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/uncontroled_component/