前言
React是一个非常灵活的前端框架,因为它不会强制开发者应用哪个自带的API或者第三方库来实现某个性能。例如React不会强制你肯定要应用Class Component或者Functional Component来开发某个组件,这齐全是开发者依据本身的场景本人决定的。而对于第三方库的应用来说,React更加没有要求,例如对于状态治理,React生态就有一堆十分受欢迎的库能够应用,例如Redux,Mobx,XState和Jotai等等。正是因为React的灵活性,React官网只说本人是一个UI library而不是UI Framework。
很强的灵活性有益处也有害处。益处是社区生态凋敝,开发者能够依据本人非凡的需要来开发满足某个非凡场景的库来配合React应用。而害处也很显著,那就是实现一样的性能抉择太多的话,对于高级开发者来说很不敌对。因为他们不晓得本人须要应用哪个原生的API或者第三方库来实现某个性能的开发。如果你选错的话,可能会导致开发出的利用有性能问题,或者升高开发效率。其实不止第三方库的应用,即便是应用原生的React API,不同的程序员写出的组件也是千差万别,代码品质也是高下不齐。基于这些起因,我打算写一系列对于React最佳实际的文章,来介绍一些React开发中常常遇到的问题,以及如何应用最佳实际来解决这些问题。理解这些最佳实际岂但能够帮你在开发的时候做更好的技术决定,还能够让你在前端面试的时候锦上添花。
本篇文章是这个系列文章的第一篇,会为大家介绍5个最佳实际。
防止大组件,要学会组件拆分
因为React对组件的大小是没有限度的,所以咱们在日常开发中可能会写出一些比拟大的组件,例如上面这个简化的例子:
下面的App组件在我看来是一个须要拆分的大组件,因为它蕴含了Nav和Content这两个子组件的全部内容,而这会导致咱们的组件难以测试和保护。对于大组件咱们的最佳实际就是按职责拆分,父组件只关怀子组件的布局问题。基于这个思路,下面的大组件能够被拆分为Nav和Content两个子组件和一个App大组件,大组件为每一个子组件创立一个wrapper div来定义它们的布局。换句话来说就是:大组件不须要关怀子组件的内容,它只须要定义子组件在其外部是如何布局的,并且传递必要的上下文信息即可。这样咱们的代码就变为:
这样写的益处是有很多,首先大组件和子组件能够别离进行测试和开发,并且子组件外部的变动和降级不会影响到大组件的代码。
如果咱们的组件切实太大,重构时大量复制粘贴代码很麻烦的话,能够应用VSCode的glean插件来自动化这个操作。Glean能够疾速帮咱们提取某段JSX代码到一个独自的组件。下图展现了如何利用glean来重构App组件:
上图中点击完Extract Component to File并填上文件名后该内容就被抽取到一个独立的组件了。
避免出现嵌套组件
我在日常工作中会看到一些程序员在一个组件外面定义另外一个组件:
下面的代码写起来确实非常不便,因为Child组件是定义在Parent组件外面的,所以它能够间接应用Parent组件外面定义的handleClick函数而不必定义和传递props。不过这种写法却有可能暗藏着重大的性能问题:Child组件会在每次Parent组件从新渲染的时候被重定义,这也就意味着旧的Child组件定义会被销毁,新的组件会被创立。对于嵌套组件咱们的最佳实际是:个别不定义嵌套组件,所有的组件都要提出父组件独自定义。基于这个最佳实际,下面的代码能够被改成:
重构完后,Child组件被独自拎进去定义,通过onClick的props承受来自父组件的handleClick函数,这岂但能够防止组件被从新定义的性能问题,还能够让咱们组件的职责更加明显和便于测试。不过这里把Child组件和Parent组件的定义都放在同一个文件其实也是一个反模式的做法,咱们马上就会说到。
每个文件只定义一个组件
在下面的例子中Child和Parent组件都被定义在了同一个文件中,这种做法在Child组件只须要被Parent组件应用的时候是没有问题的。可是如果Child组件也须要被export进去被其它组件应用的话,代码就会开始变得凌乱了,例如可能会有上面这种import语句呈现:
因而咱们这里更好的做法应该是:一个文件外面只定义一个组件。在下面的例子中就须要将Parent和Child两个组件拆分成两个文件:Parent.jsx和Child.jsx。这个最佳实际是能够用eslint-plugin-react外面的no-multi-comp规定来主动束缚的。
其实在我的团队外面,我岂但要求不同的组件定义到不同的文件外面,我还要求每一个组件都要有一个独自的文件夹,组件的定义放在它对应文件夹的index.jsx文件外面。我这样要求组员的理由是:一个React组件往往有很多配套的文件,例如单元测试,CSS Module定义或者StoryBook的Story等等。这些文件都是和组件强相干的,咱们把它们和组件文件放在一起的话有利于前面咱们对代码的重构。举个例子上面是咱们我的项目代码外面Navbar组件的目录构造:
试想一下哪天咱们我的项目不须要这个组件了,咱们只需删除Navbar这个文件夹即可,而无需放心还有和这个组件关联的逻辑散落在我的项目的其它中央。
应用useMemo来防止组件外面的反复计算
如果咱们的组件外面须要进行一些比拟消耗CPU的计算:
下面这个组件调用了expensiveCalculation函数,这个函数会在组件每次渲染的时候被调用。这外面有一个问题就是无论count字段是否扭转,这个大计算量的函数都会被调用,这其实会造成肯定水平的性能耗费。对于这个场景咱们的优化思路是应用useMemo来防止expensiveCalculation函数的反复调用,具体做法是:
useMemo这个hook能够保障只有在count这个状态变动的时候expensiveCalculation才会被调用。如果你对useMemo不够相熟的话能够参考一下我写的超具体React Hook实际指南。
防止应用无用的div
咱们晓得React是不容许咱们在组件的render外面返回一个dom数组的。因为这个起因很多开发者在写组件的时候都喜爱在最外层包一个毫无意义的div:
下面的写法会导致最终渲染在页面的无用div越来越多,这岂但会影响到咱们页面的accessibility,还可能会让无用的div烦扰咱们对页面的debug。这里咱们的最佳实际是应用React.Fragment来代替这个无用的div:
和空div不同,React的Fragment元素不会生成一个新的div,也就防止了下面说到的这些问题。每次都写React.Fragment其实不够不便,因而React为你提供了更加不便的写法:
总结
下面为大家总结了5个咱们在日常开发React利用时能够应用到的最佳实际,前面我会不断更新这个系列的内容,为大家带来更多的React最佳实际。
集体技术动静
创作不易,如果你从这篇文章中学到货色,请给我点一下赞或者关注,你的反对是我持续创作的最大能源!
同时欢送关注公众号进击的大葱一起学习成长