为什么我们需要在类组件的构造函数中绑定方法?
如果我们回到hooks还未诞生的年代,在创建 React 类组件时我们必然会遇到这样的代码。
class MyClassComponent extends React.Component {
constructor(props) {
super(props);
// Assuming that you need to pass this as a prop to one of a child component
this.someMethod = this.someMethod.bind(this); // But why? 🤔
}
...
}
这是因为每当我们需要在类组件中将函数作为 props 传递给子组件时,我们都必须执行以下操作之一:
你有没有想过,为什么事情必须这样发展?为什么我们还要做这些额外的工作?
在本文中,我将首先尝试解释构造函数内部的绑定。掌握这些知识后,我们将尝试解释为什么箭头函数不遵循相同的规则。
我们需要知道的是,构造函数中的绑定与 React 无关。它纯粹与 JavaScript 如何实现this有关。让我们看下面的代码:
var x = 10;
let foo = {
x: 90,
getX: function() {
return this.x;
}
};
foo.getX(); // prints 90
let xGetter = foo.getX;
xGetter(); // prints 10;
当我们将x初始化到全局作用域时,它就成为了window对象的属性(假设它是浏览器环境,而不是严格模式)。我们可以断言:
window.x === 10; // true
this始终指向调用该方法的对象。因此,在foo.getX()的例子中,this指向foo对象并返回值 90。而在xGetter()的例子中,this指向window对象并返回值 10。
要检索foo.x的值,我们可以通过使用Function.prototype.bind将this的值绑定到foo对象来创建一个新函数。
let getFooX = foo.getX.bind(foo);
getFooX(); // prints 90
有了这些知识,让我们尝试了解将函数 prop 传递到子组件时会发生什么。
在下面的代码示例中,我们创建了一个虚拟类组件来模拟 React 组件的思维模型。在render函数内部,我们返回一个普通的 JS 对象,该对象具有一个名为'onClick'的功能性 prop 。
React 元素只是一个不可变的描述对象,具有
两个字段:type: (string | ReactClass) 和 props: Object
class Component {
constructor() {
this.state = 10;
this.setState = function() {
console.log('state');
};
}
handleClick() {
this.setState();
}
render() {
// return a child component.
return {
type: 'button',
props: {
// pass functional props
onClick: this.handleClick,
children: 'Click Me'
}
};
}
}
// 1. creating a component instance
const componentInstance = new Component();
// 2. calling a render method on the instance
// ( In reality, React does the same thing for your class components)
const element = componentInstance.render();
// 3. calling the onClick function, which was passed as a prop,
// will throw a 'TypeError: this.setState is not a function'.
element.props.onClick();
现在这个 TypeError 很明显了,因为 this 指向的props对象并不知道 setState 函数的存在。setState函数只是 componentInstance 的一个属性。
因此,为了解决这个问题,我们必须在构造函数中绑定 handleClick 函数:
// inside constructor function
constructor() {
// bind returns a new function
this.handleClick = this.handleClick.bind(this);
}
...
// calling onClick will print 'state' this time.
element.props.onClick();
现在, this的值将始终指向具有setState作为其属性之一的componentInstance,并且不会抛出任何 TypeError。
好了,这就是我们第一个问题的答案。目前进展顺利。接下来,我们将努力找到第二个问题的答案。
查看下面的代码:
let bar = { someMethod: function() { return this; } };
bar.someMethod(); // print {someMethod: f}
let foo = { someMethod: () => this};
foo.someMethod(); // prints global 'window' object
箭头函数没有自己的 this 。它始终由创建箭头函数时其周围的作用域决定。
箭头函数没有自己的this 。
当我们在类内部使用箭头函数(使用属性初始化器功能)时,它会成为实例的方法属性。由于this始终由外部作用域决定,因此它将指向该类的实例。让我们看看实际效果:
class Component {
constructor() {
this.state = 10;
this.setState = function() {
console.log('state');
};
}
// using fat arrow function; no binding require inside constructor
handleClick = () => {
// this will now point to the instance of Component class which knows about the setState method property
this.setState();
};
render() {
// return a child component.
return {
type: 'button',
props: {
// pass functional props
onClick: this.handleClick,
children: 'Click Me'
}
};
}
}
// 1. creating a component instance
const componenttInstance = new Component();
// 2. calling a render method on the instance ( In reality, React does the same thing for your class components)
const element = componenttInstance.render();
// 3. calling onClick will now print 'state' to the console.
element.props.onClick();
希望您喜欢这篇文章,现在能够自信地回答这个问题。我强烈建议您阅读Axel Rauschmayer 博士的这篇文章,其中详细介绍了它的工作原理。this
感谢您的阅读,如果您喜欢这篇文章,那么几句❤️肯定会让我微笑😍。
链接地址:https://dev.to/aman_singh/why-do-we-need-to-bind-methods-inside-our-class-component-s-constructor-45bn