我最常遇到的 React 错误以及如何修复它们

2025-06-07

我最常遇到的 React 错误以及如何修复它们

在使用流行的 JavaScript 库React时,有些错误/问题似乎会反复出现。在大多数情况下,这些问题都可以轻松避免,我想与大家分享,以便您可以减少调试时间,将更多时间投入到代码编写中。

所以我们不要浪费时间,看看我们的问题以及如何解决它们👏。

内容

  1. 忘记在元素列表中添加键
  2. 未正确返回列表
  3. 不清除某些useEffect副作用
  4. 不包裹相邻的 JSX 元素

1)忘记在元素列表中添加键

在 React 中,我们经常会遇到需要将数据列表映射到元素或组件的情况。这通常使用Array.prototype.map函数将数组中每个索引的数据通过 props 传递给元素或组件。

如果我们不添加keyprop 就执行此操作,React 会抱怨每个元素都缺少一个key。本质上,它只是一个特殊的属性,我们向其传递一个字符串。它应该是一个唯一的字符串,以便将其与我们也映射的兄弟元素区分开来。

React 说:

键可以帮助 React 识别哪些项目已更改、已添加或已删除。数组中的元素应赋予键,以赋予元素稳定的标识。

示例问题

在向元素添加键之前,让我们映射一些数据来实际演示一下这个问题。这里我们将创建一个foods从 prop 对象解构的简单组件。foods它只是一个对象数组,如下所示 👇

我们的示例数据集

以及我们的组件👇

没有 key prop 的映射元素

最后是来自 React 👇 的警告。

缺少钥匙警告

解决方案

要解决这个问题,我们只需为返回的元素传递一个唯一的键即可。我们映射的数据通常来自获取请求,并且通常包含一个 id。幸运的是,我们有一个id可以从数据集中使用的属性。让我们添加一个key属性。

添加关键道具后

如果没有唯一的 ID,我们就需要一个替代方案。人们通常使用数组的索引作为 ,但对于列表中位置可能发生变化的任何数据集,不建议这样做。这会对组件的状态产生负面影响。有关Reactjs - Reconciliation 的key更多信息,请参阅此处

name相反,我们可以通过使用 JavaScript 对象将属性与当前日期/时间相结合来创建密钥Date

2)没有正确返回列表

回还是不回

正如我们已经看到的,在 React 中,我们经常会迭代一些数据。我们可能正在将数据集过滤到特定的子集,或者映射到 DOM。无论它是什么,在返回数据时都需要注意一些陷阱,否则我们可能会感到困惑。

示例问题

当我们将数据集映射到某些元素或组件时,我们可以看到一个令人沮丧的例子。我们期望在屏幕上看到这些元素或组件,以及我们映射到其中的数据。然而,我们什么也看不到。

没有错误,没有警告,也没有数据🤨。在这种情况下,很可能是你没有正确返回结果。

在我们的示例中,我们将食物数组映射到一些元素,以便显示给用户。它应该如下所示:

正确回车演示

相反,我们的数据似乎丢失了👇。

错误返回演示

让我给你看一些例子,在这些例子中,我们看不到预期的输出。我们将数组传递给组件,然后像以前一样从 prop 对象中解构它。

你能发现下面的问题吗?

未返回正确性的示例

正确!这里我们没有使用return关键字显式或隐式地返回任何内容。

我们再看一下👇。

第二个未正确返回的示例

这次我们添加了return关键字,但实际上我们在这里做的是返回undefined。 return 语句下面的代码永远不会被读取。

您可能会遇到其他示例,但让我们看一下可以使用的不同解决方案。

解决方案

让我们从显式返回开始。如果我们article按照 return 语句移动元素,一切就都正常了。

见下文👇

正确显式返回的示例

我们还可以用括号包裹返回元素,如下所示:

正确显式返回的示例

另一种选择是隐式返回结果,这意味着我们可以省去return语句和函数体花括号。快来看看👇。

正确的隐式返回示例

或者像这样内联👇。

正确的隐式返回示例

只要您意识到可能遇到的陷阱,选择权就在您手中。如果数据似乎缺失,请务必仔细检查地图功能,确保返回结果正确。

3)没有清除某些useEffect副作用

这个useEffect钩子允许我们在函数式组件内部执行副作用。我们在此钩子中执行的某些副作用需要清理。这意味着当组件卸载时,我们可以运行一个特殊的函数。有时这是必要的,否则我们可能会看到一个错误,警告我们应用程序存在内存泄漏。

假设useEffect一个组件在将某个状态设置为响应之前,会执行某种异步 API 调用。如果响应速度很慢,并且组件在我们收到响应之前就卸载了,那么我们可能正在尝试更新尚未安装的组件的状态。

示例问题

让我们看一下两种不同的情况,在这些情况下我们可能会对我们的添加一些清理useEffect

第一种情况是,我们的useEffect钩子中有一个异步的 fetch 请求。在我们收到 fetch 调用的响应之前,应用程序的用户导航到了另一个页面。这是我们在useEffect钩子中添加清理函数之前的组件。

清理前的 React useEffect

这里我们在组件挂载后获取一些数据,然后使用结果来设置组件状态。最后我们将状态映射到 DOM。相当简单👍。

第二种情况是我们eventListeners向某些 DOM 元素添加了一些监听器。如果组件卸载,我们需要移除这些监听器。

在我们清理之前检查一下👇

在将清理函数添加到 useEffect 之前

对于这个简单的例子,我们内部的逻辑useEffect无关紧要。重要的是我们添加了一个事件监听器,而这部分需要清理。

解决方案

我们首先添加一个清理函数,如下useEffect所示:

useEffect 清理函数

它只是一个函数,我们将其添加到钩子的底部,useEffect并在其中添加清理逻辑。

现在,为了清理我们的获取请求,我们可以使用 JavaScript 中提供的 DOM API AbortController。它允许我们中止 Web 请求,以便在组件卸载时中止获取请求。让我们看看它的实际效果👇。

React useEffect 获取清理函数

首先,我们使用构造函数创建一个控制器new AbortController(),然后将其属性 signal 传递给获取请求。将控制器信号与请求关联起来,使我们能够通过调用abort()清理函数来中止请求。

现在我们要确保不会有任何请求返回到未安装的组件。

您可能已经猜到了,我们示例中的清理函数eventListener很简单。我们需要做的就是删除在清理函数中创建的所有监听器removeEventListener。让我们看看实际效果👇。

React useEffect 监听器清理示例

希望现在你不会像我一样忘记清理你的效果😉。

4)不包裹相邻的 JSX 元素

这个很容易调试,但我认为我会把它包括在内,因为我有时会忘记这样做,直到 React 开始对我大喊大叫😅。

相邻的 JSX 元素必须用封闭标签包裹。根据我们的需求,有几种不同的方法可以做到这一点。

示例问题

如果我们希望包装器成为 DOM 的一部分,用于结构化目的,那么尽可能使用一些语义元素(<article>等等<section>)。我通常不建议用 来包装元素,<div>但如果您希望将包装器用于样式设置,那么这样做是可以的。

我们通常不希望包装器成为 DOM 的一部分,因为它在那里没有任何用处。我们只会添加一些标记来让 React 闭嘴。

让我们看看实际的问题。

示例组件未包裹相邻的 JSX

以及它抛出的错误👇

相邻的 JSX 错误

您的代码编辑器很可能在错误弹出之前就此向您发出了警告,这很好。

解决方案

幸运的是,React 为我们提供了一个解决方案。React.Fragment如果我们不需要将包装器作为 DOM 的一部分,我们可以用它来包装相邻的 JSX。假设以下示例就是这种情况。

首先让我们使用它,React.Fragment然后我们再看看如何进一步简化它。

使用 React.Fragment 包装相邻的 JSX

如果我们的片段不需要任何属性或键,我们可以将其简化React.Fragment为这个<>空标签。请看下文。

使用 React.Fragment 缩短语法包装相邻的 JSX

最后,如果我们像之前看到的那样将一些数据映射到 JSX,那么我们需要在包装元素中添加键。如果我们只有相邻的 JSX,那么我们可以用它包装元素,React.Fragment并在片段中添加一个唯一的键。

使用 React.fragment 和唯一键包装我们映射的相邻 JSX

结论

感谢您读到这里!希望您能从本文中有所收获,这样我们就能确保在以后的代码中避免这些问题。

如果你喜欢这篇文章,欢迎在文章下方点个👍。这会激励我不断改进,创作更多精彩内容。

如果您想与我联系,请来跟我打个招呼@Kieran6dev,因为我总是在 Twitter 上积极与其他开发人员交流。

谢谢!

文章来源:https://dev.to/kieran6roberts/my-most-frequent-react-errors-and-how-you-fix-them-3epp
PREV
React 组件和 Props
NEXT
编程一年了🎉。以下是一些我会回头给自己的建议