前言
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 最佳实际。
集体技术动静
创作不易,如果你从这篇文章中学到货色,请给我点一下赞或者关注,你的反对是我持续创作的最大能源!
同时欢送关注公众号 进击的大葱 一起学习成长