笔记:关于react中state的this指向
按现在来算react的学习周期只能算刚开始的前几天吧,所以这篇文章会比较杂,主要是用来记录一下学习类式组件过程中的关于state的一些问题,主要是围绕了下面问题展开的
this的指向问题
首先是绑定事件
//1.创建组件
class Person extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {
test:'true'
}
}
render() {
return <h1 onClick ={ hit }>{this.state.test}</h1>
}
}
//2.渲染组件到页面
ReactDOM.render(<Person/>,document.getElementById('test'))
//声明方法
function hit(){
console.log('点击了');
}
当我们想在 Person类组件外面的hit方法里修改状态时就会出现问题了
(更新一下代码
//1.创建组件
class Person extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {
test:'true'
}
}
render() {
return <h1 onClick ={ hit }>{this.state.test}</h1>
}
}
//2.渲染组件到页面
ReactDOM.render(<Person/>,document.getElementById('test'))
//声明方法
function hit(){
console.log('点击了');
this.state.test = 'false'
console.log(this.state.test);
}
此时点击后就会发生这么一个问题
这个问题的意思就是无法在hti方法里读取到’undenfined’里的定义的state属性
这个问题的不是说state出现了问题,而是state前面的this是undenfined
可以通过log(this)进行验证
原因很简单,由于hit是我们自定义的一个函数,而babel会在自定义函数中开启严格模式,this就是undefined
那么反过来看一下这个this是什么,首先我们可以在render里log一下看看
红色框代表的是实例的制造类、蓝色框代表的是实例本身,那么我们就可以知道了this是Person类里的实例
那么又抛出了一个问题,我们能不能拿到Person类里的实例,首先我们要知道这个实例在哪
//2.渲染组件到页面
ReactDOM.render(<Person/>,document.getElementById('test'))
看到这里,我们要了解一下这个ReactDOM.render发生了什么
1.React解析组件标签,找到了Person组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
现在我们知道了,这个实例是由React帮助new出来了,那就无法通过这个来解决问题了
现在回到Person类组件中,我们可以发现construcot和render可以触碰到实例对象,所以可以使用到this,那我们把hit方法定义到Person类里不就行了吗,来试试看
class Person extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {
test:'true'
}
}
render() {
console.log(this);
return <h1 onClick ={ hit }>{this.state.test}</h1>
}
hit(){
console.log('点击了');
console.log(this);
// this.state.test = 'false'
// console.log(this.state.test);
}
}
运行后可以发现,报错了
原来是这里出现了问题
return <h1 onClick ={ hit }>{this.state.test}</h1>
由于hit方法定义到了Person类组件里,那么它只能给Person类组件的实例调用啊,所以要改成这样,加一个this就行了
return <h1 onClick ={ this.hit }>{this.state.test}</h1>
很快可以发现,当点击后又报了一个错误 this还是undefined
这里就会有一个疑惑,为什么同时在Person类里的构造器construtor和render里的this都是实例对象,为什么hit不是呢,这与类的一些基础知识以及原型链有关
这个是有关原型链的一个图(非常有用
每个函数都会创建一个prototype属性,这个属性是一个对象, 包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。
首先我们要知道类的方法是在放在了原型对象上给实例使用的,通过一个简单的例子可以证明这个
class Person {
constructor(name){
this.name = name
}
speak(){
console.log(`名字是${this.name}`);
}
}
const p1 = new Person('lzp')
console.log(p1);
p1.speak()
我们可以看到p1实例里面并没有speak()这个方法,而是在Person这个类的原型对象上找到这个方法来执行的,我们是通过p1实例调用到的这个方法,自然而然可以得出结论
类中的方法是放到了类的原型对象上的,以提供给类的实例调用,并且哪个实例调用的这个方法,this就指向谁
回过头来在hit方法中,也可以根据这个结论说明一些事(再放一次代码
//1.创建组件
class Person extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {
test:'true'
}
}
render() {
console.log(this);
return <h1 onClick ={ this.hit }>{this.state.test}</h1>
}
hit(){
console.log('点击了');
console.log(this);
// this.state.test = 'false'
// console.log(this.state.test);
}
}
//2.渲染组件到页面
ReactDOM.render(<Person/>,document.getElementById('test'))
hit是放在了Person的原型对象上提供给实例使用的,只有通过Person实例调用hit方法时,hit里面的this才是Person的实例(这里开始会有点绕了,注意看
首先看这个
return <h1 onClick ={ this.hit }>{this.state.test}</h1>
在这里面其实根本没有调用hit这个方法,onClick ={ this.hit }是一个赋值语句,相当于通过this实例找到了hit这个方法,将它作为了onClick的回调,当你点击的时候,它并不是通过this实例来调用的,而是直接调用,同时由于babel的机制,它是undefined
那我们现在知道问题所在了,现在就可以去解决问题
我们的目的是使得hit方法里面的this是Person的实例对象,这样才能去修改state里面的值
解决方向:只有通过Person实例调用hit方法时,hit里面的this才是Person的实例,现在的hit是绑定到了Person的原型对象上了,假如把它再绑定到了Person上即可*
解决方法:
class Person extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {
test:'true'
}
this.p1_this = this.hit.bind(this)
}
render() {
return <h1 onClick ={ this.p1_this }>{this.state.test}</h1>
}
hit(){
console.log(this);
}
}
bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值
首先看右边,this.hit中的this是组件实例对象,它会在Person的原型对象上找到hit方法
再通过bing(this)方法,生成了一个新的函数,并将它的this绑定到了传进来的this上
再将此赋值给了左边的p1_this,这样Person实例自身就会多了一个新的方法叫p1_this,它与Person原型对象上的hit方法一致,只是里面的this变成了Person的实例对象
运行结果
更新:使用箭头函数可以更加简单
hit = () =>{
xxxx
}
由于也是刚刚起步,所以有很多东西在表达上没那么准确,甚至是错误,请见谅,有发现可以直接说出来,感谢大家的观看
https://www.bilibili.com/video/BV1wy4y1D7JT,文章内很多内容都是来自这个视频,我觉得他对于react的讲解十分细节,感兴趣的可以看看