React最佳实践的举例
领域驱动的设计结构而不是类型驱动的设计
- 按功能或类型来组织项目,在较小的应用程序中是可行的,但随着应用程序的增长,会有数以百计的文件被创建。如果项目没有被模块化,那么就很难找到依赖关系。例如。/redux/{action, middleware, reducers, utils}。相反,最好是按照领域来组织。
使用基于函数的组件而不是无状态的基于类的组件
- 当涉及到基于函数的组件时,React有一些性能优化。避免使用基于类的组件,除非你需要生命周期方法。
保持组件的小型化,并与特定的功能相联系--使其可预测、可测试
- 它更容易理解、更新、实现性能优化、测试并有助于促进重用性
- 大的组件往往变得难以维护、调试、测试和重构
- 超过200行代码的组件是一个很大的信号,它应该被拆分。
删减你的代码(不要重复自己的代码)
- 如果你发现任何模式或相似之处,你就有可能在重复代码。
将有状态的数据相关逻辑与表现逻辑分开。
- 将两者混在一起会导致复杂性。保持小的和孤立的责任。
所有与任何一个组件相关的文件都应该放在一个文件夹里。
- 将所有与任何一个组件有关的文件放在一个文件夹里,包括样式文件。它使层次结构易于理解,使重构和浏览代码库更容易。
严格的提示
- 提示将帮助开发人员意识到最佳和常见的做法,并养成良好的习惯。这也有助于统一代码库的风格。
不要使用Index或Value作为Key
- Key是React用来识别元素的东西。如果你推送一个项目到列表中,并且键是相同的,React就会认为该元素代表与之前相同的组件,即使它不是。这可能会破坏你的应用程序或显示错误的数据
- 每个键应该是永久的和唯一的。生成随机数更糟,因为它每次都会重新渲染组件。
- 根据官方文档,解决方案是在映射的ListItem组件中传入key,但不返回。
bind()和箭头函数
- .bind()每次运行都会创建一个新函数。这意味着每次渲染函数执行时都会创建一个新的函数。随着应用程序的增长,这对性能有影响。
- Arrow函数也有同样的问题,因为它是一个匿名函数,不能被比较。
- 解决方案?在构造器生命周期中绑定函数。
不要使用匿名函数作为处理程序
- 匿名函数不能被比较。这意味着React会一直重新渲染。只传递引用
只使用setState来改变状态。不要直接突变状态
- 如果你直接突变状态,组件将不会被重新渲染,并且变化不会被反映出来。这是因为状态是浅层比较的。你应该总是使用setState来改变状态的值。
不要使用道具作为状态
- 构造函数只被调用一次。如果改变了,状态也不会被更新。只有当你想对状态进行播种时,你才能使用这种模式。否则,这将导致真理之源的重复。直接使用props来代替。
使用React.Fragments来避免不必要的包装器填充到DOM上
- 使用React.Fragment或使用更简洁的<></>语法,而不是使用填充DOM的不必要的包装器,如div、span等。
避免在DOM元素上散布不必要的props
- 不要使用{...props},而是要更明确,否则会在DOM元素上填充属性。
避免使用内联样式
- 将样式与组件分开。由于CSS的特殊性,这也会在未来造成bug,并阻止主题化、品牌化等。
- 此外,这将导致React总是重新渲染组件,而不管数据是否有变化。
使用 "重新选择"(Reselect)来帮助防止在未改变的输入上通过备忘来重新渲染。
- 另外也可以使用React.memo。使用这个可能会更好。
使用Web Worker来完成大量的CPU任务
- Web Worker使得在后台线程中运行操作成为可能,与主线程分开。它有助于防止UI阻塞或变慢
使用可选链式
- 防止在没有防护检查的情况下访问一个子属性时发生崩溃
不要使用导出默认值--用显式代替
- 这使得重构在较大的文件中变得更加困难,而且在较大的代码库中也会减慢智能检测的速度。这似乎是一个小的代码风格偏好,但在较大的代码库中它开始成为一个问题。
使用shouldComponentUpdate来弥补数组、函数、对象等的浅层比较。
- 题外话:可以用一种笨拙但临时的方式来解决一些主要的性能问题
虚拟化长列表
- 如果你有长的列表,渲染所有的元素包括隐藏的元素会导致性能问题和停滞。使用像react-window这样的工具来虚拟长列表。
大型重构/改进
- 使用React.Memo来缓存组件。对功能组件使用它。
- Memo化的函数更快,因为如果调用的值与之前的调用相同,它将从缓存中获取返回值。
- 如果你有几个很少改变状态的组件,你应该考虑缓存它们。这就像导出默认的React.memo(ProfileView)一样简单
- 使用Reselect来缓存Redux选择器
- CSS架构
- 命名的连贯性
- 结构的一致性
- 组件的懒惰加载(后)。