文章来自我个人的Github

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

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

class App extends React.Components {state = {count: 0}clickHandler () {const count = this.state.count + 1this.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 + 1this.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 + 1this.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:
<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}@boundMethodmethod() {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}@autobindmethod() {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://juejin.im/post/5ca07af9e51d4560dc4b65e0

React Bind Handle的思考相关推荐

  1. 基于React开发范式的思考:写在Lesx发布之际

    例子:lesx-example webpack loader: lesx-loader 一些背景 现在前端框架已经呈现出React.Angular.Vue三足鼎立的局势,对于三者的对比以及技术选型的思 ...

  2. 用React的方式思考

    2019独角兽企业重金招聘Python工程师标准>>> 构建大型.反应迅捷的web app,我首选react.我们在facebook和instagram中都用了它,扩展的不错. 当你 ...

  3. 了解React.js中数组子项的唯一键

    本文翻译自:Understanding unique keys for array children in React.js I'm building a React component that a ...

  4. Flutter React编程范式实践

    作者:闲鱼技术-匠修 Flutter Widget的设计灵感来源于React,是一款原生就立足于响应式的UI框架.本文基于Flutter特点,试图结合闲鱼在Flutter的工程应用来谈下我们对Flut ...

  5. React笔记---kalrry

    React笔记---kalrry 前言 文档 一.react 1. 什么是react 2. 特点 3. react的发展史 4. cra---create-react-app 5. 拿到空项目怎么办? ...

  6. 从零开始的React学习(一)

    React基础 写在前面:这是我学习B站黑马React视频前75p所作的笔记. 后续的学习也会整理出笔记,供自己之后翻阅,也希望能给你带来一些帮助. (1)概述 ​ 用于构建用户界面的JavaScri ...

  7. React DnD简明教程

    React DnD简明教程 概述 React Dnd不同于其他的拖拽库,如果你以前没有用过它可能会被吓到.然而,一旦你了解了它设计的一些核心概念,它将变得有意义.我建议你在阅读文档其他部分之前,先阅读 ...

  8. react 最佳实践_最佳React教程

    react 最佳实践 React is a JavaScript library for building user interfaces. It was voted the most loved i ...

  9. react 数据可视化_使用d3创建数据可视化并在2020年做出React

    react 数据可视化 Data visualisation and application technologies have evolved greatly over the past decad ...

最新文章

  1. 科研赢家比其他人多了哪一个特点?
  2. 怎么计算一个对象占用的内存
  3. .Net Web项目安装包制作(三)补充说明
  4. 对Kalman Filter的理解
  5. 写给前端新手看的一些模块化知识
  6. python如果选择不在列表里_Python-list.remove(x)x不在列表中
  7. 如何判断微信内置浏览器(JS PHP)
  8. JS左侧竖向滑动菜单
  9. 名校大厂 AI 高手云集,芒果 TV 音视频算法大赛硕果累累
  10. 前端js如何生成一个对象,并转化为json字符串
  11. 如何把qq挂到云服务器,云服务器挂QQ软件常用方法和注意问题
  12. 腾讯云— LAMP 架构个人实践分享
  13. rtl驱动 ubuntu 禁用_ubuntu18.04系统中使用dkms安装wifi驱动rtl8723be的方法
  14. Markdown——图片、文字显示居中的一种方法
  15. 2020我也当了面试官-java面试题之一
  16. PO系列之 PO中使用webService
  17. SCAU高级语言程序设计OJ
  18. NOI2019滚粗记
  19. python打开摄像头_Python 调用摄像头
  20. SparkSQL之“Dataset和Dataframe

热门文章

  1. client-go删除job同时删除job关联的pod
  2. linux存储--dup和dup2函数解析(十八)
  3. vim-go开发环境Tagbar插件和NERTree插件安装
  4. cx_Oracle读写clob
  5. android 记一次富文本加载之路
  6. 页面中使用多个element-ui upload上传组件时绑定对应元素
  7. Spring 多视图配置
  8. [javaSE] 集合框架(Map概述)
  9. linux php源码包 安装openssl 和curl 扩展
  10. 关于Basware的使用随想