中级 React 开发人员的坏习惯
事实
个人意见
如果您是一名中级 React 开发人员,希望成为高级 React 开发人员,那么这篇文章适合您!
几年来,我每天都会审查初级和中级开发人员编写的 React 代码,这篇文章涵盖了我所看到的最常见的错误。我假设你已经了解 React 的基础知识,因此不会讨论像“不要修改 props 或 state”这样的陷阱。
陋习
本节中的每个标题都是您应该避免的坏习惯!
我将使用待办事项列表应用程序的经典示例来说明我的一些观点。
复制状态
每条状态都应该有唯一的真实来源。如果同一条信息在状态中存储两次,则这两个状态可能会不同步。您可以尝试编写代码来同步这两个状态,但这只是一种容易出错的权宜之计,而不是真正的解决方案。
以下是待办事项列表应用中重复状态的示例。我们需要跟踪待办事项列表中的事项以及已完成的事项。您可以在状态中存储两个数组,一个数组包含所有待办事项,另一个数组仅包含已完成的事项:
const [todos, setTodos] = useState<Todo[]>([])
const [completedTodos, setCompletedTodos] = useState<Todo[]>([])
但这段代码往坏了说是 bug 满满,往好了说是臭烘烘的!已完成的待办事项会在 state 中存储两次,所以如果用户编辑了待办事项的文本内容,而你只调用了setTodos
,completedTodos
现在返回的仍然是旧的文本,这是错误的!
有几种方法可以删除重复的状态。在这个例子中,你可以简单地completed
向Todo
类型添加一个布尔值,这样completedTodos
就不再需要数组了。
Reducer 利用率不足
React 内置了两种存储状态的方式:useState
和useReducer
。此外,还有无数用于管理全局状态的库,其中 Redux 最为流行。由于 Redux 通过 Reducer 处理所有状态更新,因此我将使用“Reducer”一词来指代useReducer
Reducer 和 Redux Reducer。
useState
当状态更新简单时,这完全没问题。例如,你可以useState
跟踪复选框是否被选中,或者跟踪value
文本输入的“”。
话虽如此,当状态更新变得稍微复杂时,你应该使用 Reducer。具体来说,当你在状态中存储数组并且用户可以编辑数组中的每个项目时,都应该使用 Reducer。在我们的待办事项列表应用中,你绝对应该使用 Reducer 来管理待办事项数组,无论是通过 ViauseReducer
还是 Redux。
Reducer 是有益的,因为:
- 它们提供了一个集中的位置来定义状态转换逻辑。
- 它们非常容易进行单元测试。
- 它们将复杂的逻辑从组件中移出,从而产生更简单的组件。
- 如果两个更改同时发生,它们会阻止状态更新被覆盖。传递一个函数
setState
是另一种防止这种情况的方法。 dispatch
由于具有稳定的身份,它们能够实现性能优化。- 他们允许你使用Immer编写变异风格的代码。你可以将 Immer 与 一起使用
useState
,但我认为实际上并没有多少人这样做。
没有为容易实现的目标编写单元测试
开发人员非常忙碌,编写自动化测试可能非常耗时。在决定是否应该编写测试时,请问自己:“这个测试是否足够有效,值得我花费时间编写它?” 如果答案是肯定的,那就编写测试吧!
我发现,中级 React 开发人员通常不会编写测试,即使测试只需 5 分钟即可编写,并且影响中等或较高!这些情况就是我所说的测试的“低垂果实”。测试低垂果实吧!
实际上,这意味着要为所有包含重要逻辑的“独立”函数编写单元测试。我所说的“独立”函数指的是定义在 React 组件外部的纯函数。
Reducer 就是一个完美的例子!代码库中任何复杂的 Reducer 都应该拥有接近 100% 的测试覆盖率。我强烈建议使用测试驱动开发 (TDD) 来开发复杂的 Reducer。这意味着你需要为 Reducer 处理的每个 Action 至少编写一个测试,并在编写测试和编写使测试通过的 Reducer 逻辑之间交替进行。
未充分利用React.memo
、useMemo
和useCallback
在许多情况下,由 React 提供支持的用户界面可能会变得滞后,特别是当您将频繁的状态更新与渲染成本高的组件配对时(React Select 和 FontAwesome,我正在关注您。)React DevTools 非常适合识别渲染性能问题,无论是使用“组件渲染时突出显示更新”复选框还是使用分析器选项卡。
对抗渲染性能低下最有力的武器是React.memo
,它仅在组件的 props 发生变化时才重新渲染组件。这里的挑战在于确保 props 不会在每次渲染时都发生变化,否则组件React.memo
将不执行任何操作。您需要使用useMemo
和useCallback
钩子来防止这种情况。
我喜欢主动使用React.memo
、useMemo
和useCallback
来预防性能问题的发生,但被动的方法——即等到发现性能问题后再进行优化——也可以奏效。
useEffect
运行频率过高或过低的编写
我对 React Hooks 唯一的抱怨是它useEffect
很容易被误用。要成为一名高级 React 开发者,你需要完全理解依赖数组的行为。useEffect
如果你没有使用React Hooks ESLint 插件,你很容易遗漏 effect 的依赖,从而导致 effect 无法按预期运行。这个问题很容易修复——只需使用 ESLint 插件并修复警告即可。
将所有依赖项都列在依赖项数组中后,你可能会发现效果运行过于频繁。例如,效果可能在每次渲染时都运行,从而导致无限更新循环。这个问题没有“一刀切”的解决方案,所以你需要分析具体情况来找出问题所在。我想说的是,如果你的效果依赖于一个函数,那么将该函数存储在 ref 中是一种很有用的模式。就像这样:
const funcRef = useRef(func)
useEffect(() => {
funcRef.current = func
})
useEffect(() => {
// do some stuff and then call
funcRef.current()
}, [/* ... */])
不考虑可用性
作为一名前端开发者,你应该努力成为不仅仅是一名程序员。优秀的前端开发者同时也是可用性和网页设计的专家,即使这些特质并没有体现在他们的职位头衔上。
可用性简单来说就是应用程序的易用性。例如,在列表中添加新的待办事项有多容易?
如果你有机会与真实用户进行可用性测试,那就太棒了。我们大多数人没有这种机会,所以我们必须根据自己对用户友好性的直觉来设计界面。这很大程度上取决于常识,以及观察你每天使用的应用程序中哪些有效,哪些无效。
以下是您今天可以实施的一些简单的可用性最佳实践:
cursor: pointer
确保可点击元素看起来可点击。将光标移到可点击元素上时,元素的颜色会略微改变,并在 CSS 中变为“指向的手”。将鼠标悬停在 Bootstrap 按钮上,即可查看这些最佳实践的实际效果。- 不要隐藏重要的 UI 元素。想象一下,一个待办事项列表应用,当删除待办事项的“X”按钮不可见时,除非你将鼠标悬停在该待办事项上。有些设计师喜欢这种“简洁”的设计,但这需要用户费力寻找才能完成一些基本操作。
- 用颜色传达含义。显示表单时,使用醒目的颜色来吸引用户对提交按钮的注意!如果有一个永久删除按钮,最好是红色的!不妨看看Bootstrap 的按钮和警告框,了解一下。
不努力掌握 CSS 和网页设计
如果你想高效地创建美观的 UI,你必须掌握 CSS 和网页设计。我不指望中级开发人员能够立即创建简洁易用的界面,同时还能保持高效率。学习 CSS 的复杂性并建立对美观的直觉需要时间。但你需要朝着这个方向努力,并随着时间的推移不断进步!
很难给出具体的技巧来提升你的样式设计技巧,但这里有一个:掌握弹性盒子 (flexbox)。虽然弹性盒子一开始可能令人望而生畏,但它是一个功能强大且用途广泛的工具,你可以用它来创建日常开发中所需的几乎所有布局。
以上就是所有坏习惯!看看你是否也犯了这些错误,并努力改进。现在,我将从宏观角度讨论一些可以提升你的 React 代码库的最佳实践。
常规最佳实践
仅使用 TypeScript
普通的 JavaScript 还算可以,但缺乏类型检查,除了小型业余项目外,其他方面都不太适合。用 TypeScript 编写所有代码将极大地提高应用程序的稳定性和可维护性。
如果你觉得 TypeScript 太复杂,那就继续学习吧。一旦你熟练掌握了,你编写 TypeScript 的速度就能和现在编写 JavaScript 一样快。
使用数据获取库
正如我在本文“坏习惯”部分所说,useEffect
正确编写 s 非常困难。尤其是在useEffect
直接从后端 API 加载数据时。使用一个抽象出数据获取细节的库,可以省去无数的麻烦。我个人更喜欢React Query,不过RTK Query、SWR和Apollo也是不错的选择。
仅在真正需要时才使用服务器渲染
服务器端渲染 (SSR) 是 React 最酷炫的功能之一。它也极大地增加了应用程序的复杂性。虽然像 Next.js 这样的框架让 SSR 变得更容易,但仍然有一些不可避免的复杂性需要处理。如果您需要 SSR 来实现 SEO 或加快移动设备的加载速度,请务必使用它。但是,如果您正在编写一个没有这些要求的商业应用程序,请使用客户端渲染。您以后会感谢我的。
将样式与组件放在一起
应用程序的 CSS 很快就会变得杂乱无章,无人能理解。Sass 和其他 CSS 预处理器虽然增加了一些实用功能,但仍然在很大程度上存在与原生 CSS 相同的问题。
我认为样式应该限定在单个 React 组件内,并将 CSS 与 React 代码放在一起。我强烈推荐阅读Kent C. Dodds 的精彩博文,了解共置的好处。将 CSS 限定在单个组件内,可以将组件复用作为共享样式的主要方式,并防止样式意外应用于错误元素的问题。
你可以借助Emotion、styled-components或CSS Modules等类似库来实现组件范围的共置样式。我个人更喜欢使用带有css
prop 的 Emotion。
更新 2022-04-15:澄清了我的声明,即当状态为数组时,应“始终”使用减速器。
文章来源:https://dev.to/srmagura/bad-habits-of-mid-level-react-developers-b41