资讯专栏INFORMATION COLUMN

React Bind Handle的思考

UnixAgain / 2178人阅读

摘要:更加需要注意的东西是无法继承带来的性能问题。看起来的确是还不错。表示不需要自动绑定的函数的名字。并且并没有成为标准,但是其实也差不多了,并不担心。结语这里的所有的解决思路都各有千秋吧。

文章来自我个人的Github
)

在平时的开发里面,总会碰到handle绑定的问题。如果你和我一样懒或者思考过,你会觉得这个过程实在是太烦了吧。这里记录一下我的思路和历程。

这里以一个按钮的点击事件来做示例。

class App extends React.Components {
    state = {
        count: 0
    }

    clickHandler () {
        const count = this.state.count + 1
        this.setState({ count })
    }

    render() {
         return (
            
        )
    }
}

这个例子的目的是点击按钮触发clickHandler来让计数器加1。我们可以用两种不同的方式来触发这个handle,因为我们使用了this.setState,所以我们都必须要给函数绑定this。亦或是使用箭头函数处理这个地方。

直接在jsx里面bind(this)

嗯 这个的确可以。但是写起来非常的长看起来也挺丑的。有个问题是每次重渲染的时候都会重新bind一次函数,对于比较大的列表来说这个地方非常不可取。

使用箭头函数

clickHandler改成如下的范式。

clickHandler = () => {
    const count = this.state.count + 1
    this.setState({ count })
}

// render ...

诶这样看起来会好很多诶。但是如果你有强迫症你会发现一件事情。如果我们加上生命周期函数和一些其他的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

如果你了解过ES7decorator。你会发现上面的写法完全可以使用decorator的形式表示,并且这个库也支持在typescript上面使用。并且结构会非常的清晰。于是你找到了autobind-decorator这个库。它能帮助到我们,给我们想要的东西,文档一开始就告诉我们。

// Before:


// After:

用之前...用之后的样子,很好就是我们要的。 这个库有个缺点就是必须的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,认为这是所有解决方案里面最好的一个了,但是要引入一个额外的依赖还是有点麻烦。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109286.html

相关文章

  • 为什么会出现React Hooks?

    摘要:尽管已经受到高度赞扬,团队仍然认为有必要构建和发布。用来描述组件的所有信息都将作为对象传递给。这是一个巨大的胜利,因为它更好地与标准保持一致。 showImg(https://segmentfault.com/img/bVbvYyy?w=880&h=369); 原文:https://dev.to/tylermcginnis/why-react-hooks-51lj.... 译者:前端...

    longshengwang 评论0 收藏0
  • VUE防抖与节流最佳解决方案——函数式组件

    摘要:案例持续触发事件时,并不立即执行函数,当毫秒内没有触发事件时,才会延时触发一次函数。也以函数形式暴露普通插槽。这样的场景组件用函数式组件是非常方便的。相关阅读函数式组件自定义指令前言 有echarts使用经验的同学可能遇到过这样的场景,在window.onresize事件回调里触发echartsBox.resize()方法来达到重绘的目的,resize事件是连续触发的这意味着echarts...

    OldPanda 评论0 收藏0
  • React模式【译】

    摘要:检查空值不要去检查是否存在某个值,快使用。当你的值是对象或者数组时,使用声明嵌套数据的预期类型。命名事件可以使用自定义事件替代预设的事件名。 原文:react-patterns 代码结构 class definition constructor event handlers component lifecycle getters render defaultProps p...

    BicycleWarrior 评论0 收藏0
  • React事件

    摘要:在中使用原生事件在中使用原生事件级事件和。的合成事件实现中,仅仅对最外层容器进行绑定,并且依赖事件冒泡完成事件委派,避免了事件捕获的浏览器不兼容特性。 Event Handler ----React事件 React中的事件包括合成事件和原生事件,React底层对合成事件进行事件委派和手动绑定,原生事件的使用在高程3有具体讲解,难点在于跨浏览器兼容和DOM0/DOM2级事件处理程序的使用...

    hearaway 评论0 收藏0
  • React事件

    摘要:在中使用原生事件在中使用原生事件级事件和。的合成事件实现中,仅仅对最外层容器进行绑定,并且依赖事件冒泡完成事件委派,避免了事件捕获的浏览器不兼容特性。 Event Handler ----React事件 React中的事件包括合成事件和原生事件,React底层对合成事件进行事件委派和手动绑定,原生事件的使用在高程3有具体讲解,难点在于跨浏览器兼容和DOM0/DOM2级事件处理程序的使用...

    Cciradih 评论0 收藏0

发表评论

0条评论

UnixAgain

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<