不要在传递 props 时使用 bind
不要在传递 props 时使用 bind
在编写 React 代码时,你经常会想要将一个函数传递给 props。通常,这是为了将回调函数传递给子组件,以便子组件可以通知父组件某个事件的发生。
重要的是要记住函数的 *绑定* – 当它被调用时,它的 this
对象将指向哪里。
有几种方法可以确保绑定正确,有些比其他方法更好。本文将介绍这些选项。
方法 #1:自动绑定(良好,仅适用于 React.createClass)
如果你正在使用 React.createClass
,组件中的成员函数会自动绑定到组件实例。你可以自由地将它们传递给其他地方,而无需调用 bind
,并且你始终传递完全相同的函数,因此没有性能损失。
var Button = React.createClass({
handleClick: function() {
console.log('clickity');
},
render: function() {
return (
<button onClick={this.handleClick}/>
);
}
});
方法 #2:在 render 中调用 .bind(糟糕,ES6)
在使用 ES6 类时,React *不会* 自动绑定组件内部的成员函数。
像这样在最后一刻进行绑定是一种使其正常工作的方法,但它会损害性能,因为每次重新渲染时都会创建一个新函数(这可能会很频繁)。
class Button extends React.Component {
handleClick() {
console.log('clickity');
}
render() {
return (
<button onClick={this.handleClick.bind(this)}/>
);
}
}
这是另一个同样糟糕的变体,每次调用 render
时都会创建一个函数
class Button extends React.Component {
handleClick() {
console.log('clickity');
}
render() {
var handleClick = this.handleClick.bind(this);
return (
<button onClick={handleClick}/>
);
}
}
方法 #3:在 render 中使用箭头函数(糟糕,ES6)
与上面的示例类似,只是这个示例使用箭头函数而不是调用 bind
。它看起来更好,但它 *仍然* 每次调用 render
时都会创建一个函数!不好。
class Button extends React.Component {
handleClick() {
console.log('clickity');
}
render() {
return (
<button onClick={() => this.handleClick()}/>
);
}
}
方法 #4:使用箭头函数的类实例字段(良好,ES8+)
这种方法通过在组件创建时将 handleClick
设置为箭头函数 *一次* 来工作。在 render
和其他函数中,this.handleClick
可以安全地传递,因为箭头函数保留了 this
绑定。
这个方法被标记为“ES8+”,因为它在技术上不属于 ES6 *或* ES7(又名 ES2016)的一部分。ES2016 已完成,并且仅包含 Array.prototype.includes
和指数运算符,因此如果它最终进入规范,它可能会是 ES2017(ES8)或更高版本。
即使 Babel 支持此功能,但仍存在(很小)风险,该功能可能会从规范中删除并需要进行一些重构,但很多人都在使用它,因此它似乎很可能保持不变。
class Button extends React.Component {
// Use an arrow function here:
handleClick = () => {
console.log('clickity');
}
render() {
return (
<button onClick={this.handleClick}/>
);
}
}
方法 #5:在构造函数中绑定(良好,ES6)
你可以在构造函数中设置绑定一次,然后永久使用它们! 别忘了调用 super
。
class Button extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('clickity');
}
render() {
return (
<button onClick={this.handleClick}/>
);
}
}
方法 #6:使用装饰器(良好,ES8+)
有一个名为 autobind-decorator 的不错的库,可以做到这一点
import autobind from 'autobind-decorator';
class Button extends React.Component {
@autobind
handleClick() {
console.log('clickity');
}
render() {
return (
<button onClick={this.handleClick}/>
);
}
}
@autobind
装饰器绑定 handleClick
方法,一切就绪。 你甚至可以在整个类上使用它,如果你很懒的话
import autobind from 'autobind-decorator';
@autobind
class Button extends React.Component {
handleClick() {
console.log('clickity');
}
handleOtherStuff() {
console.log('also bound');
}
render() {
return (
<button onClick={this.handleClick}/>
);
}
}
再次说明,ES2016/ES7 不包含此功能,因此即使 Babel 支持它,你也在承担一些风险,通过在代码中使用它。
总结
这涵盖了绑定传递给 props 的函数的方式。你知道其他方法吗? 有你最喜欢的方法吗? 在评论中告诉我们。
不要在传递 props 时使用 bind 最初由 Dave Ceddia 在 Angularity 上于 2016 年 7 月 05 日发布。