上节课我们学习了如何初始化state
,而且也介绍了如何在我们的组件中来调用state
,在上节课的Demo
中呢,我们已经完全可以做到用state
来展示在页面上,但是我们却依然还是只能展示了这个静态页面,我们想要的点击事件却依然还是没能成功实现,当时是哇了一个坑,那么这节课我们来填坑了。
回顾
按照老规矩啊,在填坑之前我们肯定还是要对上节课的内容来做一个简单的回顾。
- 如果通过
state
来驱动页面需要借助构造器方法 - 构造器方法的形参官方给定的是
props
- 构造器方法要在第一步将
props
传给super
state
的类型十一个对象- 通过
this
可以来调用到state
添加点击事件
我们回想一下,上节课我们已经成功地通过state
来驱动页面展示,但是我们那个点击文字完成状态切换还没有实现。
如果要实现这个点击切换状态的功能,我们的最起码的前提是什么呢?
那我肯定得让这段文字支持点击操作啊,我这段文字连点击操作都不支持还怎么往下进行啊?
那么第一步,我们就给这段文字添加上点击事件
原生js
事件绑定
在学习react
事件绑定之前,我们来回忆一下,原生js
做事件绑定都有那些方法呢?
例如我现在页面上有三个按钮,分别叫按钮1
,按钮2
,按钮3
,我现在要求这三个按钮点击的时候都会有一个弹窗展示。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>bind</title> </head> <body> <button id="btn1">按钮1</button> <button id="btn2">按钮2</button> <button>按钮3</button> <script type="text/javascript"> </script> </body> </html>
这个我们该怎么去实现呢?第一种方式我们先用最繁琐的一个方式来处理一下
const btn1 = document.getElementById("btn1"); btn1.addEventListener("click", () => { alert("按钮1被点击了"); });
我们来看一下效果怎么样:
不难看出这种方法是可以很成功地实现我们的需求,但是我们也知道其实还有一个我们很熟悉的方式来添加点击事件的。没错,就是onclick
,那么我们就用这个方式来写按钮2吧。
const btn2 = document.getElementById("btn2"); btn2.onclick = () =>{ alert("按钮2被点击了"); }
我们来看一下这方法的效果:
很显然,这个方法也是没有毛病的,但是还有没有其他的方式呢?我们的按钮3要怎么写呢?
<button onclick="notify()">按钮3</button> <script type="text/script"> function notify() { alert("按钮3被点击了"); } </script>
我们直接给按钮3添加了一个onclick
属性,至于是什么意思呢?就是我们点击了按钮3,程序就会去调用onclick
属性中的函数。但是用这个方式的话就需要我们在js
中定义相关的函数了。我么莱卡一下具体效果。
也是很正常的展示了我们预期的结果。
以上便是原生js
来添加点击事件的方法。
react
添加点击事件
我们通过上文了解了通过原生js
添加点击事件,那么在react
中我们的点击事件又该怎么添加呢?
其实理论上来讲,js
中的那 3 种方法都可以用的。但是我们还记不记得react
的一个特点啊?操作虚拟DOM
来代替操作真实DOM
。
而我们之前按钮1
,按钮2
使用的方法那不就是在操作真实DOM
嘛。这就很不符合react
的设计哲学了。那我们可想而知,在react
中那是大理推崇按钮3
的方法的。
那么我们就来试试呗:
class Weather extends React.Component { constructor(props) { super(props); this.state = { isHot: false } } render() { return <h2 onclick="notify()">今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h2> } } ReactDOM.render(<Weather/>, document.getElementById("test")); function notify() { console.log("标题被点击了!"); }
看我们上面那一段代码。前面的构造器方法我们就不赘述了,看render
方法里面,<h2>
标签我们给添加了onclick
属性,onclick
属性执行的是notify
函数,然后下面我们定义了notify
函数。
当然这次我们就不弹窗了,就在控制台打印信息吧,方便我们测试多次点击。
来看一下效果:
报错了,这你说想不到的事情,但是我们看看报错信息怎么说的:不允许使用onclick
属性,你想要用的是不是onClick
属性?注意这是大写的C
。
当然了我们这里也顺带提一句,react
还干了一件事儿,就是所以html
和js
里的on***
监听属性都给重写了一遍,所有的这一类属性on
后面的首字母必须大写,比如onclick
要写成onClick
,onblur
要写成onBlur
。这是硬性规定。当然在以后的内容我们也会再深入一点去探讨为什么,现在我们先记住,埋个伏笔在这。
那么好这种事情我们之前是不是也遇到过类似的,既然官方提醒我们是不是要用onClick
那我们就改过去试一试呗。
我们也按要求改了,但是诶,还是不对,告诉我们onClick
属性呢必须是一个函数,但是我们获取到的却是string
类型。那么好吧我们再改一下
class Weather extends React.Component { ... render() { return <h2 onClick={notify()}>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h2> } } ReactDOM.render(<Weather/>, document.getElementById("test")); function notify() { alert("标题被点击了!"); }
那我这次总行了吧?而且我还是很规矩地用{}
把notify
函数给括起来了。那么来看:
或许大家发现我上面代码把console.log
改成了alert
,为了方便观察,因为下面的现象有点意思
因为这一次页面还没来得及渲染成功就已经弹窗了。也就是说在渲染页面之前就调用了notify
函数。
这是为什么呢?
我们来回顾一下react
渲染组件的流程:
react
解析组件标签- 发现组件是类定义的,随后实例化类
- 通过类组件的实例对象调用
render
方法
到这就够了,调用了render
方法,render
方法要return
虚拟DOM
出来啊,也就是return
关键字后面的jsx
代码就会直接被执行,然后把结果return
出来。所以说这里代码执行了,但是页面还没被渲染。
可能有人说,这一段没怎么理解,jsx
代码执行了怎么就会调用notify
函数呢?那我们来看一下这段jsx
代码:
这段代码<h2 onClick={notify()}>...</h2>
,这段代码其实再简单不过了,就是一个标签嘛。但是onClick={notify()}
这一步是肯定要被执行的吧,不执行的话onClick
属性没有意义啊。
而且notify()
被{}
括起来了这代表这什么啊?我们回忆一下前面所说的,{}
是为了引入js
表达式。所以说这一步就是一个赋值表达式啊,notify()
这个表达式就是在调用notify
函数。这一段就是把notify
函数的返回值赋值给onClick
,所以说会出现这种在还没有渲染页面就出现函数调用的情况。
而且我们再看一下notify
函数的代码:
function notify() { console.log("标题被点击了!"); }
这玩意儿有返回值吗?当然有,undefined
就是它的返回值啊。也就是说在渲染出来的页面中<h2>
标签的onclick
属性将是undifined
,这也就意味着接下来页面上的<h2>
标签再怎么点击都不会有反应,因为你点击调用的是undefined
。
那么我们怎么处理呢?
早在上一次报错官方就已经暗示我们了,onClick
得是一个函数。那么怎么才能是函数呢?那把后面的小括号去掉不就得了嘛。我们再来看看:
class Weather extends React.Component { ... render() { return <h2 onClick={notify}>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h2> } } ReactDOM.render(<Weather/>, document.getElementById("test")); function notify() { console.log("标题被点击了!"); }
这么一写,我的onClick
属性就被赋值为notify
这个函数,而不是notify
函数的返回值了。那么我们再来看一下最终的结果:
页面渲染出来了,我还没有点击,控制台也什么都没有。
我多次点击,控制台也统计出了我的点击次数。
以上便是react
添加点击事件的方法。但是这样的话我们是不是就可以修改state
从而驱动页面了呢?大家可以先试一下,我们接下来的内容再深入讨论。
总结
- 原生
js
添加点击事件有三种方法 addEventListener
方法onclick
方法onclick
属性配合回调函数react
中允许使用原生js
中的方法react
不推荐使用addEventListener
和onclick
,大力推崇onClick
属性配合回调函数react
中onClick
属性中click
首字母必须大写onClick
属性不能用引号括起来,需要用{}
括起来onClick
属性必须是函数,所以函数名后面不可以加()
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/react_event_bind/