当前位置: 首页 > Web前端 > HTML

面试官可能会问你React的最佳实践(一)

时间:2023-03-28 19:02:45 HTML

前言React是一个非常灵活的前端框架,因为它不强制开发者使用哪个内置的API或第三方库来完成某个任务功能。例如,React并没有强制要求你使用ClassComponent或FunctionalComponent来开发某个组件,这完全由开发者根据自己的场景来决定。对于第三方库的使用,React没有任何要求。例如,对于状态管理,React生态系统有一堆非常流行的库可以使用,例如Redux、Mobx、XState和Jotai。正是因为React的灵活性,React官网只说它是一个UI库而不是UIFramework。极大的灵活性既有优点也有缺点。好处是社区生态繁荣,开发者可以根据自己的特殊需求开发出满足特殊场景的库与React配合使用。缺点也很明显,就是如果实现同一个功能的选项太多,对初级开发者很不友好。因为他们不知道自己需要使用哪个原生API或者第三方库来完成某个功能的开发。如果选错了,可能会导致开发的应用出现性能问题,或者降低开发效率。事实上,不仅是第三方库的使用,即使是原生的ReactAPI,不同程序员编写的组件也是千差万别,代码质量也参差不齐。基于这些原因,我打算写一个关于React最佳实践的系列文章,介绍React开发中经常遇到的一些问题,以及如何使用最佳实践来解决这些问题。了解这些最佳实践,不仅可以帮助你在开发时做出更好的技术决策,还可以让你在前端面试中如虎添翼。本文是本系列的第一篇,将向您介绍5个最佳实践。避免大组件,学习拆分组件由于React对组件的大小没有限制,我们在日常开发中可能会写一些比较大的组件,比如下面这个简化的例子:上面的App组件在我看来是一个大组件需要拆分的组件,因为它包含了Nav和Content这两个子组件的全部内容,这会让我们的组件难以测试和维护。对于大型组件,我们最好的做法是按职责拆分,父组件只关心子组件的布局。基于这个思路,上面的大组件可以拆分成两个子组件Nav和Content,以及一个大的App组件。大组件为每个子组件创建一个包装器div来定义它们的布局。也就是说:大组件不需要关心子组件的内容,它只需要定义子组件在它内部如何布局,并传递必要的上下文信息即可。这样,我们的代码就变成了:这样写的好处很多。首先,大组件和子组件可以分别进行测试和开发,子组件内部的改动和升级不会影响到大组件的代码。如果我们的组件太大,重构的时候复制粘贴很多代码很麻烦,我们可以使用VSCode的glean插件来自动化这个操作。Glean可以快速帮助我们将某段JSX代码提取到一个单独的组件中。下图展示了如何使用glean来重构App组件:点击ExtractComponenttoFile并填写上图中的文件名后,内容就会被抽取成一个独立的组件。避免组件嵌套在日常工作中,会看到一些程序员在一个组件中定义另一个组件:上面的代码写起来确实方便,因为在Parent组件中定义了Child组件,所以可以直接使用定义的handleClick函数在Parent组件中不需要定义和传递props。但是,这种写法可能会隐藏严重的性能问题:每次重新渲染Parent组件都会重新定义Child组件,这意味着旧的Child组件定义将被销毁并创建一个新的组件。.我们对嵌套组件的最佳实践是:一般情况下,嵌套组件是不定义的,所有组件都必须由父组件单独定义。基于这个最佳实践,上面的代码可以改成:重构后,单独定义Child组件,通过onClickprops接受来自父组件的handleClick函数,这样不仅可以避免组件的性能问题被重新定义,也可以让我们的组件的职责更清晰,更容易测试。但是,将Child组件和Parent组件的定义放在同一个文件中实际上是一种反模式,我们稍后会谈到。每个文件只定义一个组件。在上面的示例中,子组件和父组件定义在同一个文件中。当Child组件只需要被Parent组件使用时,这种方式是没有问题的。但是,如果Child组件也需要被导出并被其他组件使用,那么代码就会开始变得混乱。例如,可能会出现如下导入语句:因此,我们这里更好的做法应该是:只在一个文件中定义一个组件。在上面的例子中,Parent和Child组件需要拆分成两个文件:Parent.jsx和Child.jsx。这个最佳实践可以被eslint-plugin-react中的no-multi-comp规则自动约束。其实在我的团队中,我不仅要求不同的组件定义在不同的文件中,而且我还要求每个组件都有一个单独的文件夹,组件的定义放在其对应文件夹的index.jsx文件中..之所以问组员,是因为一个React组件往往有很多支持文件,比如单元测试,CSSModule定义,或者StoryBook的Story等等,这些文件和组件是强相关的,如果我们把它们放在一起组件文件,这将有助于我们稍后重构代码。例如下面是我们项目代码中Navbar组件的目录结构:想象一下,有一天我们的项目不需要这个组件,我们只需要删除Navbar文件夹,而不用担心这个组件相关的逻辑散落在别处在项目中。使用useMemo避免组件中的重复计算如果我们需要在我们的组件中执行一些CPU密集型计算:上面的组件调用了expensiveCalculation函数,每次渲染组件时都会调用该函数。这里的一个问题是不管count字段是否发生变化都会调用这个计算量大的函数,这实际上会造成一定程度的性能消耗。对于这种场景,我们的优化思路是使用useMemo来避免expensiveCalculation函数的重复调用。具体方法是:useMemohook可以保证expensiveCalculation只有在count的状态发生变化时才会被调用。如果你对useMemo不熟悉,可以参考我超详细的ReactHook实战指南。避免使用无用的div我们知道React不允许我们在组件的渲染中返回一个dom数组。为此,很多开发者在编写组件时喜欢在最外层包裹一个无意义的div:如上写法会导致最终渲染到页面上的无用div越来越多,不仅会影响我们页面的质量可访问性,它也可能使无用的div干扰我们对页面的调试。我们这里的最佳实践是使用React.Fragment来替换这个无用的div:与空的div不同,React的Fragment元素不会生成新的div,从而避免了上述问题。每次都写React.Fragment并不方便,所以React为大家提供了一种更方便的写法:总结以上总结了我们日常开发React应用可以用到的5个最佳实践,我会持续更新后续本系列内容为大家带来更多React最佳实践。创造个人技术动力并不容易。如果你从这篇文章中学到了什么,请给我点赞或关注。您的支持是我继续创作的最大动力!同时欢迎关注公众号攻略葱一起学习成长