bind、this、箭头函数

一个古老的坑

<Form
    submit={this.submit.bind(this)}
>
</Form>
复制代码

这种代码想必很多同学都见过,当我要将组件内部的方法绑定在dom上进行执行调用的时候,为了绑定this的作用域,经常会这么写。

但是最近听同事的一个分享,才知道原来bind也是有坑的。

MDN Document

"The bind() function creates a new function (a bound function) with the same function body as the function it is being called on with the this value bound to the first argument of bind(), which cannot be overridden."

MDN上的说法是:bind会创建一个新函数,其第一个参数作为绑定的this,这个this是不会被覆盖的。

然而同事碰到的bug恰好就是因为使用bind绑定this之后,在函数中的this与我们的预期不符的情况。

这个坑持续了非常长的一段时间,一直有零星的反馈,但是一直查不出原因,包括在windows各种浏览器中做兼容性测试时也没能成功复现。

前段时间终于找到一个可以稳定复现这个bug的用户,远程操作了一下他们的电脑,最后发现是上面this.submit函数中有一个value值,这个值在其他所有地方都正常,但是在Form表单submit的时候就丢失,变成了undefined。最终判定为bindthis作用域在个别版本的浏览器中会与预期不一致所导致的,最终将bind的写法改成箭头函数之后就恢复正常了。

不过虽然碰到了这种坑,但是我自己查了很多资料,并没有发现具体哪些个别版本的浏览器会有这种问题,因此只能在以后写代码的时候尽可能少的使用bind方法去绑定this

绑定this的写法

<Button onClick={this.handleClick.bind(this)}>click me</Button>
<Button onClick={() => this.handleClick()}>click me</Button>
复制代码

一般我们在组件中绑定this,经常会使用以上两种写法,但是其实以上两种写法不太符合react的书写规范,原因有两种:

  1. this的指向不是很明确。
  2. bind和箭头函数都会返回一个新函数,每次父组件rerender的时候都会导致子组件rerender

react官方推荐的写法是在constructor中绑定this,或直接在组件中使用箭头函数声明方法。

class App extends Component {
    constructor() {
        this.handleClick = this.handleClick.bind(this);
    }
    handleSubmit = () => {
        
    }
    render() {
        return (...);
    }
}
复制代码

这样我们就可以避免子组件不必要的重渲染了。

带参数的方法

这个时候我们又会遇到下一个问题,如果我们碰到需要带参数的方法怎么办?

比如点击按钮,我们需要根据id标识来删除一个元素。

这个时候我们也有两种选择,第一种就是将参数所需要的值绑定到对应dom元素的value上,这样我们就可以通过e.target.value来取值了。

export default class Toggle extends Component {
  deleteButton = (e) => {
    const id = e.target.value;
  }
  render() {
    const { user } = this.props;
    return (
      <button onClick={this.deleteButton} value={user.id}>Toggle Button</button>
    );
  }
}
复制代码

第二种方法是在外层再套一层函数用于处理点击事件的e参数,其他的参数在函数内部处理和传递。

export default class Toggle extends Component {
  deleteButton = (id) => {
    // ...
  }
  handleDeleteButton = e => {
    const id = this.props.user.id;
    this.deleteButton(id);
  }
  render() {
    return (
      <button onClick={this.deleteButton} value={user.id}>Toggle Button</button>
    );
  }
}
复制代码
吐槽

虽然知道原理,也知道为了减少性能损失要尽量少的在绑定dom的方法的时候使用bind和箭头函数,但是真的很爽啊![狗头]

长期招人广告

今日头条国际化团队长期招人啦~

实习生和社招都要,什么岗位都缺~

简历请投递至liufeixiang@bytedance.com

[滑稽]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值