react系列-bind this

react系列-bind this

问题

对于大多数前端开发来说,JavaScript 的 this 关键字会造成诸多困扰,由于 JavaScript 代码中的 this 指向并不清晰。在写react应用时,也会也到很多作用域绑定引起的问题,React组件ES6的写法,不会将方法内部的作用域自动绑定到组件的实例上。

下面展示一段问题代码

class Search extends Component {
    static propTypes = {
        onSearch: React.PropTypes.func.isRequired
    }
    onSearch() {
        console.log('表单值:', this.field.getValues());
        this.props.onSearch(this.field.getValues());
    }
    render(){
        const {init} = this.field;
        return <div>
            <Form direction="hoz" labelAlign="left">
                    <FormItem label="loginID:">
                        <Input placeholder="请输入loginID" {...init('loginID')}/>
                    </FormItem>
                    <Button type="primary" onClick={this.onSearch}>搜索</Button>
            </Form>
        </div>
    }
}

如果你真的尝试这么做了, 你会发现在onSearch中,因为this指向的是全局对象window而报错。

解决办法

我们都知道常规改变函数作用域的无非3种(Fiontion.prototype.bind call apply 三兄弟),下面讲解一下在es6中bind作用域的几种方式。

  1. 使用Function.prototype.bind()
    class Search extends Component {
        render(){
            return <div>
                <Form direction="hoz" labelAlign="left">
                        <FormItem label="loginID:">
                            <Input placeholder="请输入loginID" {...init('loginID')}/>
                        </FormItem>
                        <Button type="primary" onClick={this.onSearch.bind(this)}>搜索</Button>
                </Form>
            </div>
        }
    }
  2. ES7函数绑定语法

    在 ES7 中,有一个关于 bind 语法 的提议,提议将 :: 作为一个新的绑定操作符, 而且已经收录在stage-0提案中,实际上::是Function.propotype.bind()的一种语法糖。 幸运的是,Babel已经提供了对这个新语法的支持。

    class Search extends Component {
        render(){
            return <div>
                <Form direction="hoz" labelAlign="left">
                        <FormItem label="loginID:">
                            <Input placeholder="请输入loginID" {...init('loginID')}/>
                        </FormItem>
                        <Button type="primary" onClick={::this.onSearch}>搜索</Button>
                </Form>
            </div>
        }
    }
  3. 在构造函数中bind this
    class Search extends Component {
        constructor(props) {
            super(props);
            this.onSearch = this.onSearch.bind(this)
        }
        render(){
            return <div>
                <Form direction="hoz" labelAlign="left">
                        <FormItem label="loginID:">
                            <Input placeholder="请输入loginID" {...init('loginID')}/>
                        </FormItem>
                        <Button type="primary" onClick={this.onSearch}>搜索</Button>
                </Form>
            </div>
        }
    }
  4. 使用箭头函数
    class Search extends Component {
        render(){
            return <div>
                <Form direction="hoz" labelAlign="left">
                        <FormItem label="loginID:">
                            <Input placeholder="请输入loginID" {...init('loginID')}/>
                        </FormItem>
                        <Button type="primary" onClick={(...args)=>{
                            this.onSearch( ...args)
                        }}>搜索</Button>
                </Form>
            </div>
        }
    }
  5. core-decorators.js

    core-decorators.js 为开发者提供了一些实用的 decorator,其中实现的autobind修饰器能使得方法中的this对象绑定到原始对象

class Search extends Component {
    @autobind
    onSearch() {
        console.log('表单值:', this.field.getValues());
        this.props.onSearch(this.field.getValues());
    }
    render(){
        const {init} = this.field;
        return <div>
            <Form direction="hoz" labelAlign="left">
                    <FormItem label="loginID:">
                        <Input placeholder="请输入loginID" {...init('loginID')}/>
                    </FormItem>
                    <Button type="primary" onClick={this.onSearch}>搜索</Button>
            </Form>
        </div>
    }
}

总结

比较

这里我们讨论下以上几种将this绑定到react组件方案的缺点,优点自己体会吧。

方案1和方案2,缺点也很严重,这种方式破坏了组件的pure render,每次组件render时,子组件Button的onClick值都是重新赋值所得,会导致Button做一次无谓的render。而且函数绑定语法::属于es7草案中的特性,尚未纳入es标准。使用需要谨慎。

方案3和方案4会增加代码量

方案5需要引入第三方库,不过core-decorators.js提供了很多使用的装饰器。

场景

某些场景下,我们需要传递额外的参数,比如列表中删除操作,需要传id。常用的方案是方案1和方案4

// Function.prototype.bind()
<Item onClick={this.doDelete.bind(this, id)}>删除</Item>
// 箭头函数
<Item onClick={(...args)=>{
    this.doDelete(id, ...args)
}}>删除</Item>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值