小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
二倍速刷 B 站 # 尚硅谷2021版React技术全家桶 视频,记录一下有趣的一些点吧。(习惯看文章和看文档,现刷视频感觉有点不适应,单口相声老师讲的很好,讲的太细但也不错。)
React 类式组件中的 this
先来看一个 React 类式组件:
class Weather extends React.Component {
constructor(props) {
super(props)
this.state = {isHot: true}
this.changeWeather = this.changeWeather.bind(this)
}
render() {
const { isHot } = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
}
changeWeather() {
console.log(this)
}
}
ReactDOM.render(<Weather/>, document.getElementById('test'))
复制代码
附:
ReactDOM.render
方法负责解析找到类,然后 new 出该类的组件实例,并调用其 render 方法。
构造方法中 this.state
哪里来的?
由代码可知 Weather
类继承于 React.Component
,在 constructor
方法中打印 this
(下图)可以看到 state: null
,说明 state
属性在 React.Component
中的 constructor
方法中已经被定义且初始化赋值为 null。同样 React 初始化的核心属性还有:context、props、refs...
因此我们可以直接在 Weather
类的构造方法里面,使用 this 去访问 state 并且给它赋值。
render 方法中 this.state
解构赋值?
按照 ES6 语法规则 render
方法定义是为实例方法,挂载在 Weather
原型上。
因为 render 方法是由 Weather 类组件实例调用的,所以它的 this 就是 Weather 组件实例,因此可以进行解构赋值,然后访问到该实例构造方法中定义的实例属性值为 isHot: true
。
JSX 中的事件绑定 onClick={this.changeWeather}
?
render 方法里面返回了 JSX:return <h1 onClick={this.changeWeather}></h1>
。有没有想过,为什么不是 return <h1 onClick={changeWeather}></h1>
?为什么需要 this 去访问?
这个问题很简单,其实是类的基础知识,changeWeather
方法是 Weather 类的实例方法,因此要通过 this
的方式去调用。
通过 JSX 事件绑定调用的 changeWeather
方法中的 this
?
当我们注释掉构造方法中的 this.changeWeather = this.changeWeather.bind(this)
然后点击触发 changeWeather
方法,发现控制台打印出来的 this
为 undefined
。这是为什么呢?明明在 render 方法里面打印的 this 是当前实例。
这个属于 this 绑定中的隐式丢失,那什么是 this 的隐式丢失?
let obj = {
a: 42,
foo: function() {
console.log(this.a);
}
};
// 函数别名
let bar = obj.foo;
obj.foo(); // 42
bar(); // undefined
复制代码
最常见的就是这种函数别名导致的隐式丢失,bar()
相当于 window
调用 foo
,window
中没有 a 变量,就会返回 window
,那为什么上面返回 undefined
呢?其实是在严格模式下会返回 undefined
。(而上面 React 案例中返回 undefined
也是因为 Babel 转换在方法内开启了严格模式。)
JSX 代码中 <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
的 this.changeWeather
只是通过类的实例对象沿着原型链找到了 changeWeather
方法并交给 onClick
作为回调,此时没有调用这个方法。等真正点击的时候,只是从堆里面把方法拿出来执行。
因此我们需要在构造函数的时候将 this 进行硬绑定:this.changeWeather = this.changeWeather.bind(this)
。从右到左分析这个代码,右边的 this.changeWeather
是原型链上,使用 bind 绑定当前实例然后返回一个新函数,并赋值给 this.changeWeather
挂在实例自身的 changeWeather 上。