Javascript React.js ES6避免绑定';这';每种方法
最近,我开始修补React.js,我喜欢它。我从普通的ES5开始,为了掌握窍门,所有的文档都是用ES5编写的 但现在我想试试ES6,因为它光鲜亮丽,而且看起来确实简化了一些事情。让我非常困扰的是,对于我添加到组件类中的每个方法,我现在都必须将“this”绑定到,否则它就无法工作。因此,我的构造函数最终看起来是这样的:Javascript React.js ES6避免绑定';这';每种方法,javascript,reactjs,ecmascript-6,Javascript,Reactjs,Ecmascript 6,最近,我开始修补React.js,我喜欢它。我从普通的ES5开始,为了掌握窍门,所有的文档都是用ES5编写的 但现在我想试试ES6,因为它光鲜亮丽,而且看起来确实简化了一些事情。让我非常困扰的是,对于我添加到组件类中的每个方法,我现在都必须将“this”绑定到,否则它就无法工作。因此,我的构造函数最终看起来是这样的: constructor(props) { super(props); this.state = { ...some initial state... } this.s
constructor(props) {
super(props);
this.state = { ...some initial state... }
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
}
// common function:
function bind(self,methods){
for(var key in methods){
self[key] = methods[key].bind(self);
}
}
// your class:
class MyClass {
constructor() {
bind(this,{
someHandler1(event){
//...
},
someHandler2(event){
//...
}
})
}
}
如果我在我的类中添加更多的方法,这将是一个更大、更丑陋的烂摊子
我的问题是,有没有办法绕过这个问题,或者至少让它更简单、更短、更不难看?我想尝试使用ES6进行React的一个主要原因是使我的代码更简洁,但这恰恰相反。如果您有任何建议或意见,我们将不胜感激。您可以使用它在构造函数之外进行绑定。它们看起来如下所示:
class Foo extends React.Component {
handleBar = () => {
console.log('neat');
};
handleFoo = () => {
console.log('cool');
};
render() {
return (
<div
onClick={this.handleBar}
onMouseOver={this.handleFoo}
/>
);
}
}
类Foo扩展了React.Component{
车把=()=>{
console.log('neat');
};
handleFoo=()=>{
console.log('cool');
};
render(){
返回(
);
}
}
Babel通过its实验性地支持类字段,但它们仍然是“实验性”的,因为它们是a(尚未在Babel预设中)
但是,在ES7或在Babel中启用该功能之前,您需要手动进行绑定。巴贝尔在的博客文章中简要介绍了这一主题。艾伦的建议很好,但如果你想要另一种方式,有:
class AppCtrlRender extends Component {
binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }
render() {
var isMobile = this.state.appData.isMobile;
var messages = this.state.appData.messages;
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
React 1.3 Slider
<br/><br/>
<div className='FlexBoxWrap'>
<Slider isMobile={isMobile}/>
<JList data={messages}/>
</div>
</div>
);
}
}
var getAppState = function() {
return {
appData: AppStore.getAppData()
};
};
export default class AppCtrl extends AppCtrlRender {
constructor() {
super();
this.state = getAppState();
this.binder('appStoreDidChange');
}
componentDidMount() {
var navPlatform = window.navigator.platform;
Actions.setWindowDefaults(navPlatform);
}
componentWillMount() { AppStore.onAny(this.appStoreDidChange); }
componentWillUnmount() { AppStore.offAny(this.appStoreDidChange); }
appStoreDidChange() { this.setState(getAppState()); }
}
类AppCtrlRender扩展组件{
binder(…methods){methods.forEach((method)=>this[method]=this[method].bind(this));}
render(){
var isMobile=this.state.appData.isMobile;
var messages=this.state.appData.messages;
返回(
反应1.3滑块
);
}
}
var getAppState=函数(){
返回{
appData:AppStore.getAppData()
};
};
导出默认类AppCtrl扩展AppCtrlRender{
构造函数(){
超级();
this.state=getAppState();
此.binder('appStoreDidChange');
}
componentDidMount(){
var navPlatform=window.navigator.platform;
Actions.setWindowDefault(导航平台);
}
componentWillMount(){AppStore.onAny(this.appStoreDidChange);}
componentWillUnmount(){AppStore.offAny(this.appStoreDidChange);}
appStoreDidChange(){this.setState(getAppState());}
}
您可以将任意数量的方法添加到此.binder('method1','method2',…)另一种选择是使用装饰器。您在原型上声明了一个getter,并且在第一次访问实例时,它使用该函数的绑定版本定义了自己的属性 但是有一个陷阱!在开发过程中,它不会取代属性,它会绑定到每个访问这意味着您不会破坏react hot loader。至少对我来说,这很重要 我创建了一个库,它提供了这一点
import {bound} from 'class-bind';
class App {
constructor(){
this.foo = 'bar';
}
@bound
returnsFoo(){
return this.foo;
}
render(){
var returnsFoo = this.returnsFoo;
return (
<div>
{returnsFoo()} === 'bar'
</div>
);
}
}
如果使用
stage-0
,则存在函数绑定语法
class MyComp extends Component {
handleClick() { console.log('doing things') }
render() {
return <button onClick={::this.handleClick}>Do Things</button>
}
}
类MyComp扩展组件{
handleClick(){console.log('doing things')}
render(){
回报
}
}
这会将结构分解为This.handleClick.call(This),我认为这通常已经足够了。一个避免绑定的方法
class MyComp extends Component {
render() {
return <button onClick={e => this.handleClick(e)}>Do Things</button>
}
}
类MyComp扩展组件{
render(){
返回这个。handleClick(e)}>做事情
}
}
免责声明:未经测试也无法轻松处理多个参数(在本例中,只有一个,事件(e))
此外,根据这篇可能值得一读的文章,这个答案可能是不应该做什么的一个例子:
实际上,我更喜欢通过将父上下文传递给子对象来模拟OOP继承
class Parent extends Component {
state = {happy: false}
changeState(happy) {
this.setState({happy})
}
render() {
return (
<Child parent={this} >
)
}
}
class Child extends Component {
//...
this.props.parent.changeState(true)
}
类父级扩展组件{
state={happy:false}
改变状态(快乐){
this.setState({happy})
}
render(){
返回(
)
}
}
类子扩展组件{
//...
this.props.parent.changeState(true)
}
$0.02,
Jon我创建了一个方法来组织所有的“绑定”
我使用一个helper函数
doBinding(this)
,我在每个构造函数中调用它。在本例中,它绑定\u handleChange1()
和\u handleChange2()
即使您不使用Babel,该方法也可以工作
我的处理程序方法都以\u
开头(表示它们是私有的约定)。因此doBinding()
查找\u
。如果不使用此约定,可以删除if(key.startsWith(“\u”)
function doBinding(obj) {
const proto = Object.getPrototypeOf(obj);
for (const key of Object.getOwnPropertyNames(proto)) {
if (key.startsWith("_")) {
obj[key] = obj[key].bind(obj);
}
}
}
使用一个公共函数执行如下绑定工作如何:
constructor(props) {
super(props);
this.state = { ...some initial state... }
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
}
// common function:
function bind(self,methods){
for(var key in methods){
self[key] = methods[key].bind(self);
}
}
// your class:
class MyClass {
constructor() {
bind(this,{
someHandler1(event){
//...
},
someHandler2(event){
//...
}
})
}
}
你真的在某处使用你所有的方法作为处理程序吗?这也是从一个更高级别的组件中获取的,所以是的,它们都在层次结构的某个地方使用。我试图遵循他们的理念,试图最好地弄清楚哪个组件需要知道什么,这就是我最终得到的结果。但不是(不应该)它们可以作为组件对象上的方法调用,而不是作为函数传递?我个人使用decorators()为了这个而不是类属性初始值设定项。谢谢。那太可惜了。我使用gulp作为我的构建系统,而gulp包似乎没有这个选项。关于如何让它更容易接受,有什么建议吗?哦,是的,你可以。我用
babel({stage:0})运行它
它成功了。这似乎是一个暂时的解决方案,因为它还处于早期阶段,但目前效果会很好。谢谢你的帮助。@Brandon它们也有同样的效果<
// common function:
function bind(self,methods){
for(var key in methods){
self[key] = methods[key].bind(self);
}
}
// your class:
class MyClass {
constructor() {
bind(this,{
someHandler1(event){
//...
},
someHandler2(event){
//...
}
})
}
}