从 React 绑定 this,看 JS 语言发展和框架设计

在 javascript 语言中,关于 this 这个关键字的行为一直以来困扰着一代又一代初级开发者。同时 this,也充分反应了 javascript 的诡异与灵活。

但是请别误会,这篇文章并不会对 this 的特征进行全方位讲解,因为这些内容都可以在各种前端书籍中找到答案。这里,我试图结合 React 事件处理函数关于 this 绑定的演化史,谈一谈这个框架设计以及 javascript 语言在这一细节上的进步和完善。同时对比 this 绑定的不同方案,让大家对 React 、ES next 有一个更清晰的认识。

React 处理 this 上下文环境已经有至少五年历史了。五年期间,方案辈出,我们先来总结一下。

方法一:React.createClass 自动绑定

React 中创建组件的方式已经很多,比较古老的诸如 React.createClass 应该很多人并不陌生。当然,从 React 0.13 开始,可以使用 ES6 Class 代替 React.createClass 了,这应该是今后推荐的方法。
但是需要知道,React.createClass 创建的组件,可以自动绑定 this。也就是说,this 这个关键字会自动绑定在组件实例上面。

// This magically works with React.createClass
// because `this` is bound for you.
onChange = {this.handleChange}

当然很遗憾,对于组件的创建,官方已经推荐使用 class 声明组件或使用 functional 无状态组件:

Later,classes were added to the language as part of ES2015,so we added the ability to create React components using JavaScript classes. Along with functional components,JavaScript classes are now the preferred way to create components in React.

For your existing createClass components,we recommend that you migrate them to JavaScript classes.

我认为,这其实是 React 框架本身的自我完善和对未来的迎合,是框架和语言发展的大势所趋。

方法二:渲染时绑定

通过前文,我们知道最传统的组件创建方式不会有 this 绑定的困扰。接下来,我们假定所有的组件都采取 ES6 classes 方式声明。这种情况下,this 无法自动绑定。一个常见的解决方案便是:

onChange = {this.handleChange.bind(this)}

这种方法简明扼要,但是有一个潜在的性能问题:当组件每次重新渲染时,都会有一个新的函数创建。OMG! 这听上去貌似是一个很大的问题,但是其实在真正的开发场景中,由此引发的性能问题往往不值一提(除非是大型组件消费类应用或游戏)。

方法三:箭头函数绑定

这种方法其实和第二种类似,拜 ES6 箭头函数所赐,我们可以隐式绑定 this:

onChange = {e => this.handleChange(e)}

当然,也与第二种方法一样,它同样存在潜在的性能问题
下面将要介绍的两种方法,可以有效规避不必要的性能消耗,请继续阅读。

方法四:Constructor 内绑定

constructor 方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。

所以我们可以:

constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
}

这种方式往往被推荐为“最佳实践”,也是笔者最为常用的方法。

但是就个人习惯而言,我认为与前两种方法相比,constructor 内绑定在可读性和可维护性上也许有些欠缺。
同时,我们知道在 constructor 声明的方法不会存在实例的原型上,而属于实例本身的方法。每个实例都有同样一个 handleChange,这本身也是一种重复和浪费。

如果你对 ES next 一直抱有开放的思想,且能够使用 stage-2 的特性,不妨尝试一下最后一种方案。

方法五:Class 属性中使用 = 和箭头函数

这个方法依赖于 ES next 的新特性,请参考 tc 39: Public Class Fields

handleChange = () => {
      // call this function from render 
      // and this.whatever in here works fine.
};

我们来总结一下这种方式的优点:

  • 使用箭头函数,有效绑定了 this;

  • 没有第二种方法和第三种方法的潜在性能问题;

  • 避免了方法四的组件实例重复问题;

  • 我们可以直接从 ES5 createClass 重构得来。

总结

本文在对比 React 绑定 this 的五种方法的同时,也由远及近了解了 javascript 语言的发展:从 ES5 的 bind, 到 ES6 的箭头函数,再到 ES next 对 class 的改进。

React 作为蓬勃发展的框架也同样在与时具进,不断完善,结合语言特性的发展不断调整着自身。

最后,我们通过这张图片来完整回顾:

本文参考了 Cory House 的文章:5 Approaches for Handling this,并在此基础上进行延伸。

我的其他一些关于 React 文章:

Happy Coding!

PS: 作者Github仓库,欢迎通过代码各种形式交流。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom