需要避免的 ReactJs 错误做法

2025-05-24

需要避免的 ReactJs 错误做法

有很多文章和博客都包含关于如何正确行事的实用信息。最佳实践、良好的设计模式、简洁的代码风格、正确的状态使用等等……
因此,我决定反其道而行之,寻找一些不该做的事情!
本文将列举一些不好的做法,并将它们整合成一篇引人入胜的文章。

使用状态来处理过多的事情

useState虽然使用或创建的 ReactJS 状态useReducer很有用,但并非所有内容都应该放在其中。很多新开发者都对这个概念感到困惑。他们不知道什么时候应该把内容放入状态,什么时候不应该。

一个例子是将本应从状态派生的数据存储在状态中。假设你有一个状态,表示网上商店中已填满的购物车。不好的做法是将总价也设置到状态中。你可以直接根据状态计算出总价。

简单的计算任务或变量正是出于这个特定原因而存在的。通常的想法是在状态中存储尽可能少的数据。在将数据放入状态之前,先问问自己是否可以从其他存储的变量或状态中获取所需的数据。

在不需要时使用 Redux

我不得不把这个 React 开发者永恒的争论放在这里。开发者们经常会问:“我应该用 Redux 还是 Context?”,“用 Context 代替 Redux 就好”或者“Context 能很好地替代 Redux 吗?”
有很多工具和机制可以部分地完成 Redux 的功能。简而言之,这解释了上面提到的问题和说法。
让我们尝试一劳永逸地解决这个争论。

Redux 与 Context
很多开发者倾向于认为 Context 本身就是一个状态管理系统。其实不然!Context 是一种依赖注入机制。
你可以在其中放入任何你想要的内容,如果你这样实现它,它就能变成一个状态管理系统。你必须使用useStateand/or useReducerhook 来管理其中的状态。这样,你就可以决定状态的存放位置,并处理如何更新它以及你希望在何处使用它。Context
的设计初衷就是避免数据在多层组件之间传递。如果你只需要解决这个问题,那么使用 Context 就足够了。

Redux 与缓存
如今,大多数应用程序都需要某种形式的缓存来保存服务器状态。
如果我们坚持使用 REST API,那么有几个库可以为您完成缓存。例如,React Query或 Vercel 的swr都非常适合 REST API。
如果我们使用更现代的 GraphQL 方法,那么使用Apollo Client进行缓存会非常容易。
如果缓存是您应用中的唯一必需品,那么您的应用中就不需要 Redux 了。

那么 Redux 是用来做什么的呢?
Redux 是一个通用的状态管理工具。它同时拥有许多用例。最引人注目的是:缓存状态、UI 状态、客户端的复杂数据管理、中间件等等。
最终,这取决于你构建的应用程序试图解决的具体问题。通常,你只需要 Redux 的部分功能(全局状态管理、缓存)。

在组件内声明组件

这是非常糟糕的,原因如下:

  1. 代码变得高度耦合。内部组件变得依赖于父组件的作用域。
  2. 内部组件几乎不可复用。你无法导出内部组件,只能将它们作为 props 传递到作用域的更底层,这很不理想。
  3. 性能。在每个父组件渲染时,内部组件的声明函数都会被重新创建。进一步解释一下,内部组件的生命周期方法将在每个渲染周期被调用。除了性能问题之外,先前的状态也会丢失。

将组件保存在各自的文件中以避免出现此问题。

在初始状态下使用道具(在某些情况下)

请记住,使用 React 官方文档中通用组件(例如计数器组件)的初始状态是完全没问题的。更详细地说,这意味着将 props 设置为 state,以便使用非响应式 prop 来初始化组件的状态。

除了提供的示例之外,初始 React 状态不应设置为响应式 prop 的值。为什么?因为除非调用状态设置器 setState 函数,否则该状态不会改变。如果上层的 props 发生变化,组件将获取更改后的 props,但状态将保持与初始 props 值相同。
这个问题破坏了组件中使用的单一真实来源概念。这是一种不好的做法,应该避免。

使用索引作为键

在 React 中,您可以使用方法渲染多个项目array.map。键必须是唯一的,以便 React 能够正确地跟踪该元素或组件。如果您使用索引作为键,则在某些情况下该键可能会重复,应该避免这种情况。
想象一下,您有一个要渲染的项目数组.map,并使用索引作为键。此外,想象一下在数组中间添加或删除一个项目。键最终会与之前相同,并且 React 会假定它是与之前相同的元素/组件。
这可能会导致不良后果,应该避免。

频繁使用扩展运算符

扩展运算符的用例非常丰富。如果使用得当,它可以帮助我们精简代码,并以更清晰的方式管理代码。在声明可重用组件、创建可重用数据的新数据对象,甚至在将参数传递给函数时,扩展运算符都非常有用。
然而,很多时候,开发人员会错误地在 props 上使用扩展运算符,并在组件上设置错误或不需要的 props。这可能会导致控制台中显示以下错误:
扩展运算符潜在错误

不使用 useEffect、useMemo 和 useCallback 依赖项

上述 React hooks 引入了依赖项的概念。依赖项只是一个包含项目的数组,当这些项目发生变化时,会导致 hooks 更新。如果你没有管理过依赖项,管理起来可能会有点棘手。依赖项数组应该包含反映 hooks 的项目,并且不应该包含太多这样的项目。ESLint
静态分析有一个规则可以帮助我们在这些 hooks 中使用依赖项。

useEffect如果您打算在组件安装时使用一次,则依赖项数组只能为空。

进行过早的优化

进行优化通常是一件好事,但不应事事都进行优化。为了充分发挥记忆化的优势,需要使用诸如useMemooruseCallback和 even 之类的钩子PureComponents。开发人员需要高度专注,并谨慎地实现记忆化,否则,记忆化可能会逐一被破坏。
下图说明了一切:
记忆纸牌屋

错误地声明 TypeScript 类型

我们大多数人都已经爱上了 TypeScript,如果没有它,JS 开发就无法进行。此外,我们大多数人都知道诸如anynever和 之类的关键字unknown。Unknown
表示所有可能值的集合,任何值都可以分配给该类型的变量。它是any 的类型安全对应项
。Never 表示空集,这意味着不能为这种类型的变量分配任何值。
大多数情况下都应该避免使用这些关键字。这一点再怎么强调也不为过。开发人员往往会对 TypeScript 感到沮丧,然后只需编写其中一个关键字来摆脱困境。这是一种不好的做法,应该避免。

这些关键词是有使用场合的,但应该尽量少用:

  • never在没有或不应该有值的位置使用。
  • unknown在有值的地方使用,但它可能具有任何类型。
  • any如果您确实需要一个不安全的逃生舱口,请使用。

结论

今天我们遇到了许多糟糕的模式,并讲解了如何避免它们,以及如何使用正确的模式。如果你学会避免这些糟糕的模式,你的程序员生涯将会轻松很多,也能避免很多 bug 和潜在的重构。

非常感谢您的阅读!

资源:
https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html
https://isamatov.com/react-derived-state/
https://changelog.com/posts/when-and-when-not-to-reach-for-redux
https://blog.logrocket.com/when-to-use-never-and-unknown-in-typescript-5e4d6c5799ad/
https://levelup.gitconnected.com/react-best-practices-avoiding-bad-practices-fefe6062787d

文章来源:https://dev.to/bornfightcompany/bad-reactjs-practices-to-avoid-a1b
PREV
如何成为一名独立的前端开发人员
NEXT
50 个 Bootstrap 5 管理仪表板模板 2024。