笔记:关于react中state的this指向

笔记:关于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的实例对象
运行结果
![(https://img-blog.csdnimg.cn/2021070420235013.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NYUFBQ,size_16,color_FFFFFF,t_70)
更新:使用箭头函数可以更加简单
hit = () =>{
xxxx
}

由于也是刚刚起步,所以有很多东西在表达上没那么准确,甚至是错误,请见谅,有发现可以直接说出来,感谢大家的观看
https://www.bilibili.com/video/BV1wy4y1D7JT,文章内很多内容都是来自这个视频,我觉得他对于react的讲解十分细节,感兴趣的可以看看

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值