文章来自我个人的
Github)
在日常平凡的开辟内里,总会遇到handle
绑定的题目。假如你和我一样懒或许思考过,你会以为这个进程实在是太烦了吧。这里纪录一下我的思绪和进程。
这里以一个按钮的点击事宜来做示例。
class App extends React.Components {
state = {
count: 0
}
clickHandler () {
const count = this.state.count + 1
this.setState({ count })
}
render() {
return (
<button>
Click me to show something in dev tools
</button>
)
}
}
这个例子的目标是点击按钮触发clickHandler
来让计数器加1
。我们能够用两种差别的体式格局来触发这个handle
,由于我们运用了this.setState
,所以我们都必需要给函数绑定this
。亦或是运用箭头函数
处置惩罚这个处所。
直接在jsx
内里bind(this)
<button onClick={this.clickHandler.bind(this)}>
Click me to show something in dev tools
</button>
嗯 这个确实能够。然则写起来异常的长看起来也挺丑的。有个题目是每次重衬着
的时刻都邑从新bind
一次函数,关于比较大的列表来讲这个处所异常不可取。
运用箭头函数
把clickHandler
改成以下的范式。
clickHandler = () => {
const count = this.state.count + 1
this.setState({ count })
}
// render ...
<button onClick={this.clickHandler)}>
Click me to show something in dev tools
</button>
诶如许看起来会好许多诶。然则假如你有强迫症你会发明一件事变。假如我们加上性命周期函数和一些其他的handler … 比方如许。
componentDidMount () {}
componentWillMount () {}
componentWillUpdate () {}
clickHandler = () => {
const count = this.state.count + 1
this.setState({ count })
}
antoherHandle = () => {}
你会发明这里性命周期函数和handler
的写法不一样。然则你确实能够让它们变得一样,比方把性命周期函数改成箭头函数。但是这看起来不会以为很奇异吗。毕竟你一直以来都不是这么做的。
除此之外箭头函数没法被继续,这意味着假如你的子组件须要继续函数,这将会致使没法做到。越发须要注重的东西是没法继续带来的机能题目。这会致使每次建立组件都邑建立新的要领致使分外的开支(由于箭头函数的完成实际上是直接在constructor
函数里丢要领),假如是经由过程继续,那末它们这些要领老是来自同一个prototype
,js编译器是会做优化的。
细致文章能够看这一篇Arrow Functions in Class Properties Might Not Be As Great As We Think。
在组织器内里运用bind(this)
经由过程组织器来写绑定函数实在看起来是不错的
constructor (props) {
super(props)
this.clickHandler = this.clickHandler.bind(this)
this.antoherHandle = this.antoherHandle.bind(this)
}
既处理了机能(内存)的题目。还能做许多有意思的事变比方说,应用现有的要领增添更有语义化的要领。
constructor (props) {
super(props)
this.clickHandler = this.clickHandler.bind(this)
this.antoherHandle = this.antoherHandle.bind(this)
this.clickWithOne = this.clickHandler.bind(this, 1)
}
如许就可以发生每次都邑传参数1
的新事宜。看起来确实是还不错。然则依然有题目。当你的要领线性的增添的时刻,假如有三个四个五个六个的时刻,你能够须要一个一个的绑定。增添它们到组织函数内里,更蹩脚的多是经由过程复制粘贴之前写的要领,你会绑定毛病的函数。就像如许。
constructor (props) {
super(props)
this.clickHandler = this.clickHandler.bind(this)
this.antoherHandle = this.antoherHandle.bind(this)
this.clickWithOne = this.antoherHandle.bind(this, 1)
}
你必需在运转的时刻才晓得你的clickWithOne
绑定的实际上是antoherHandle
。假如你没测试过,那末极能够就会涌现一些你难以明白的题目或许bug。
自动绑定
假如你动脑想一想会发明能够写一个autobind
的要领来自绑定函数呀。然则你很懒没有去写,你经由过程github
搜刮到了一个叫做React-autobind的库。看起来彷佛还不错。
constructor(props) {
super(props);
autoBind(this);
}
以至能够不绑定某些要领。
constructor(props) {
super(props);
autoBind(this, {
wontBind: ['leaveAlone1', 'leaveAlone2']
});
}
或许指定只绑定某些要领。
constructor(props) {
super(props);
autoBind(this, {
bindOnly: ['myMethod1', 'myMethod2']
});
}
看起来似乎是妙极了。然则你会发明这个写法实在照样很烦琐啊。要写一坨东西。。翻开源码看一眼你会发明有一个默许的wonbind
列表。
let wontBind = [
'constructor',
'render',
'componentWillMount',
'componentDidMount',
'componentWillReceiveProps',
'shouldComponentUpdate',
'componentWillUpdate',
'componentDidUpdate',
'componentWillUnmount'
];
示意不须要自动绑定的函数的名字。然则这个列表异常的蹩脚,由于跟着React版本的提拔,某些钩子和要领都邑被烧毁,跟着时候能够还会增添增加的要领。
这个库也很久没更新了。差评照样摒弃吧。。。
Autobind-decorator
假如你相识过ES7
的decorator
。你会发明上面的写法完全能够运用decorator
的情势示意,而且这个库也支撑在typescript
上面运用。而且构造会异常的清楚。因而你找到了autobind-decorator这个库。它能协助到我们,给我们想要的东西,文档一开始就通知我们。
// Before:
<button onClick={ this.handleClick.bind(this) }></button>
// After:
<button onClick={ this.handleClick }></button>
用之前…用以后的模样,很好就是我们要的。 这个库有个瑕玷就是必需的IE11+以上的版本才支撑,然则这实在也还好。
别的就是你的开启decorator
的支撑在babel
的设置内里。
{
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
]
}
我们来看看引荐的用法。
import {boundMethod} from 'autobind-decorator'
class Component {
constructor(value) {
this.value = value
}
@boundMethod
method() {
return this.value
}
}
let component = new Component(42)
let method = component.method // .bind(component) isn't needed!
method() // returns 42
给要领绑定this,而不是全部类,这么做是越发合理的。由于不是每一个要领都须要用到this
的。如Dan
所说。
It is unnecessary to do that to every function. This is just as bad as autobinding (on a class). You only need to bind functions that you pass around. e.g.
onClick={this.doSomething}
. Or
fetch.then(this.handleDone)
— Dan Abramov
既能够在函数上,也能够在类上运用的@autobind。
import autobind from 'autobind-decorator'
class Component {
constructor(value) {
this.value = value
}
@autobind
method() {
return this.value
}
}
let component = new Component(42)
let method = component.method // .bind(component) isn't needed!
method() // returns 42
// Also usable on the class to bind all methods
// Please see performance if you decide to autobind your class
@autobind
class Component { }
只能作用于类的@boundClass,我们不免也会有全都须要绑定到this
的状况这时刻我们直接boundClass
会越发的简约。
import {boundClass} from 'autobind-decorator'
@boundClass
class Component {
constructor(value) {
this.value = value
}
method() {
return this.value
}
}
let component = new Component(42)
let method = component.method // .bind(component) isn't needed!
method() // returns 42
瑕玷也是有的,并不能像constructor
那样本身马马虎虎的定差别的要领名经由过程原有的要领,必需的写出一个新的,然则这是小题目,无伤大雅。而且descorator
并没有成为规范,然则实在也差不多了,并不忧郁。
结语
这里的一切的处理思绪都各有所长吧。怎样弃取照样看本身,这里就不逐一列出来各自的对比了 ,于我个人而言会偏好Autobind-decorator
,以为这是一切处理方案内里最好的一个了,然则要引入一个分外的依靠照样有点贫苦。