截至 2017 年 11 月,我知道了几种将方法绑定(bind)到 React 组件的方法,以便 this
关键字指向拥有该方法的 React 元素(例如,在事件处理程序中是必需的)
<强>1。在构造函数中绑定(bind)
class A extends React.Component {
constructor(props) {
super(props)
this._eventHandler = this._eventHandler.bind(this)
}
_eventHandler() {
// ...
}
render() {
return <div onClick={this._eventHandler} />
}
}
<强>2。 render() 中的箭头函数
class A extends React.Component {
_eventHandler() {
// ...
}
render() {
return <div onClick={()=>{this._eventHandler()}} />
}
}
<强>3。在 render() 中绑定(bind)
class A extends React.Component {
_eventHandler() {
// ...
}
render() {
return <div onClick={this._eventHandler.bind(this)} />
}
}
<强>4。类字段中的 ES2015 箭头函数
class A extends React.Component {
_eventHandler = () => {
// ...
}
render() {
return <div onClick={this._eventHandler} />
}
}
<强>5。 @autobind 装饰器
class A extends React.Component {
@autobind
_eventHandler() {
// ...
}
render() {
return <div onClick={this._eventHandler} />
}
}
1 是最安全的方式,因为它不需要通过 babel 进行构建时转换,但输入起来很烦人。
2 和 3 具有性能影响,因为绑定(bind)发生在每个渲染器和 React diff 算法上
4 和 5 比 1 需要更少的输入,但它们需要 babel 的支持并且可能不是最终规范的一部分然而。除此之外,我非常反对注释的想法(来自 Java 后端背景我鄙视注释,因为它们经常被过度使用并且过于神奇)
从最新的 Babel 版本开始,4 或 5 是推荐的和最安全的(关于 future 兼容性)绑定(bind)函数的方式吗?还有其他我不知道的方法吗?我应该继续使用 1 吗?此外,如果这些被认为可以安全使用,是否有任何代码模块可以更改我的代码库以使用它们?
编辑:@LucaFabbri 指向 reflective bind巴别塔变换。它看起来很酷,但它需要一个非标准的 babel-plugin,我不喜欢它,因为它不是很安全。我尽量避免构建时魔法,如果你长时间只在一个代码库上工作,它们很好用,但如果你维护多个代码库,你每次都需要处理构建时魔法(加上在不弹出的情况下不支持 create-react-app。
最佳答案
如果构造函数中的绑定(bind)(方法 1)对您来说太烦人,我认为首选方法是类字段上的箭头函数(方法 4),因为它是一个简单的 babel 转换,it's a stage 3 proposal (基本上面向 future ),并避免了方法 2 和 3 的性能问题(如果您希望利用 shouldComponentUpdate
或 PureComponent
。
您可能不知道的一种方法是我想出的方法(还没有看到其他人有类似的东西),专门用于在对某些对象执行 .map
时避免方法 2 和 3数据数组以呈现需要在 Prop 上传递 this.someInstanceMethod(withSomeArg)
的组件列表。例如:
class CatList extends React.Component {
static propTypes = {
kitties: PropTypes.arrayOf(PropTypes.instanceOf(Cat)),
}
adoptKitty(cat) {
this.setState({ loading: true })
return api.adopt(cat)
.then(res => this.setState({ loading: false })
.catch(err => this.setState({ loading: false, err })
}
render() {
// ... other stuff ...
{this.props.kitties.map(kitty => (
<PureKittyCat
key={kitty.id}
// ... the problem:
onClick={() => this.adoptKitty(kitty)}
/>
))}
}
}
目前还不清楚如何避免像这样在 .map
中传递 props 上的函数文字,不仅因为您需要绑定(bind) this
,而且您还需要将当前元素传递给实例方法。在这种情况下,大多数人只会放弃将 PureKittyCat
变成 React.PureComponent
的想法。
我对这个问题的解决方案是在 Component 实例上存储一个 WeakMap 以创建一个本地缓存(父组件的本地缓存),它将每个 kitty
对象与我想传递给关联的 PureKittyCat
组件。它看起来像这样:
class CatList extends React.Component {
static propTypes = {
kitties: PropTypes.arrayOf(PropTypes.instanceOf(Cat)),
}
this.methodCache = new WeakMap()
adoptKitty(cat) {
this.setState({ loading: true })
return api.adopt(cat)
.then(res => this.setState({ loading: false })
.catch(err => this.setState({ loading: false, err })
}
render() {
// ... other stuff...
{this.props.kitties.map(kitty => {
// ... the good stuff:
if ( !this.methodCache.has(kitty) ) {
this.methodCache.set(kitty, {
adopt: () => this.adoptKitty(kitty),
// any other methods you might need
})
}
// as long is this is the same in-memory kitty, onClick will
// receive the same in-memory function object every render
return (
<PureKittyCat
key={kitty.id}
onClick={this.methodCache.get(kitty).adopt}
/>
)
})}
}
}
对于像 avoid a memory-leak 这样的事情,WeakMaps 是正确的选择.并且在组件上存储新缓存而不是作为全局缓存(在其自己的模块中)避免了如果/当您尝试为同一对象缓存同名方法时遇到名称冲突的可能性(此处 Cat
s) 跨多个组件。
这里解释了我见过的这个问题的唯一其他解决方案:https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36 .
两者都涉及一些烦人的设置,但这确实是针对该场景实现渲染优化的唯一方法。
关于javascript - 在 React Components 中绑定(bind)方法的首选方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47569487/