在 React 中进行 API 调用的权威指南

了解如何处理 Web 应用程序中的 API 调用是一项至关重要的技能。有很多不同的库可以帮助您完成这个过程,但有时它们对初学者不是很友好。

使用 vanilla JavaScript 时,您可能会使用 Fetch 或 Axios 等库来发出 API 请求。在 React 中你也可以使用它们,挑战在于如何围绕这些库组织代码,使其尽可能可读、可扩展和解耦。

这不是一个非常直观的任务。对于刚开始使用 React 的新开发人员来说,发出这样的 API 请求是很常见的:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// ❌ Don't do this</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">UsersList</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">users</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setUsers</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">([]);</span>

  <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/users</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setUsers</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">users</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">[]);</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">users</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">map</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">user</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">user</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span>
      ))}
    <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
  );
};
</code></span></span>

上述方法有效,甚至在业务级代码库中也很常见。但是使用它有一些缺点:

  • 数据存储在本地状态
    • 其他组件中的每个 API 调用都需要一个新的本地useState
  • 组件中直接调用请求库(Fetch)
    • 例如,如果将库更改为 Axios,则每个组件都需要重构
    • 这同样适用于端点,如果它发生变化,你需要在很多地方重构它
  • 在展示组件中发出服务器级请求
    • 组件旨在呈现数据,而不是处理获取逻辑
    • 对每个组件、类和函数承担单一责任是一种很好的做法
  • 不清楚请求将返回什么
    • 您依靠端点名称来了解 API 将返回什么

有很多不同的方法可以解决这些问题。今天,我将向您展示我的想法和方法,以创建可靠且可扩展的文件夹和文件结构,您甚至可以在 Next.js 等框架上应用它或它背后的想法。

我们示例的场景

为了理解和结合所有概念,让我们逐步构建一个 Grocery List 应用程序。该应用程序将具有以下功能:

  • 列出现有项目;
  • 添加新项目;
  • 除去项目;
  • 将项目标记为已完成;

对于样式,我将使用TailwindCSS。为了模拟 API 请求,将使用Mirage JS ,这是一个非常易于使用且有用的 API 模拟库。要调用此 API,我们将使用Fetch

所有示例都在我的GitHub上,所以请随意克隆存储库并使用它。README 文件中描述了如何运行它的详细信息。

最终结果将如下所示:

创建 API 端点

此应用程序将需要 4 个 API 端点:

扫描二维码关注公众号,回复: 15434101 查看本文章
  1. GET /api/grocery-list- 检索所有项目
  2. POST /api/grocery-list- 创建一个新项目
  3. PUT /api/grocery-list/:id/done- 将 id 等于 :id 的项目标记为完成
  4. DELETE /api/grocery-list/:id- 删除 id 等于 :id 的项目

以下示例是调用 API 的最基本情况。它不是最好的,但我们会在进行过程中重构代码,因此您会更好地理解所有概念。此外,我们不关注表示层,即组件的实际 JSX。它肯定可以改进,但这不是本文的重点。

1.检索所有项目

添加第一次调用的好地方是在useEffect组件的 上,并添加一个refresh状态作为参数,所以每次这个状态改变时,我们都会重新获取项目:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">([]);</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refetch</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setRefetch</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/api/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
      <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">())</span>
      <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">);</span>
      <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">]);</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">map</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span> <span style="color:var(--syntax-name-color)">key</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)">))</span><span style="color:var(--syntax-string-color)">}</span>
    <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
  <span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

2.创建一个新项目

当用户输入项目标题并单击“添加”按钮时,应用程序应调用 API 以创建新项目,然后再次获取所有项目以显示新项目:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">""</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleAdd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">preventDefault</span><span style="color:var(--syntax-text-color)">();</span>

    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/api/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">POST</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
      <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">({</span> <span style="color:var(--syntax-name-color)">title</span> <span style="color:var(--syntax-text-color)">}),</span>
    <span style="color:var(--syntax-text-color)">}).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">""</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Empty the title input</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Force refetch to update the list</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-comment-color)">// ...</span>

    <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">form</span> <span style="color:var(--syntax-name-color)">onSubmit</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">handleAdd</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span>
        <span style="color:var(--syntax-name-color)">required</span>
        <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"text"</span>
        <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">target</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span>
        <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
      <span style="color:var(--syntax-text-color)">/></span>
      <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"submit"</span><span style="color:var(--syntax-text-color)">></span>Add<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">button</span><span style="color:var(--syntax-text-color)">></span>
    <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">form</span><span style="color:var(--syntax-text-color)">></span>

    <span style="color:var(--syntax-comment-color)">// ...</span>
  <span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

3. 将项目标记为已完成

当用户单击复选框以将项目标记为完成时,应用程序应分派一个 PUT 请求,将其item.id作为参数传递到端点上。如果该项目已标记为已完成,则我们无需提出请求。

这与创建新项目非常相似,只是请求方法发生了变化:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`/api/grocery-list/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/done`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">PUT</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">}).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Force refetch to update the list</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-comment-color)">// ...</span>

    <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">map</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span> <span style="color:var(--syntax-name-color)">key</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
          <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
            <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Checkbox to mark the item as done */</span><span style="color:var(--syntax-string-color)">}</span>
            <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span>
              <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"checkbox"</span>
              <span style="color:var(--syntax-name-color)">checked</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-string-color)">}</span>
              <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span>
            <span style="color:var(--syntax-text-color)">/></span>
            <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
          <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)">))</span><span style="color:var(--syntax-string-color)">}</span>
    <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>

    <span style="color:var(--syntax-comment-color)">// ...</span>
  <span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

4.删除项目

这与我们将项目标记为完成时所做的几乎相同,但使用的是 DELETE 方法。单击“删除”按钮时,应用程序应调用一个函数来调度 API 调用:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleDelete</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`/api/grocery-list/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">DELETE</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">}).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Force refetch to update the list</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-comment-color)">// ...</span>

    <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">map</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span> <span style="color:var(--syntax-name-color)">key</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
          <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
            <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Checkbox to mark the item as done */</span><span style="color:var(--syntax-string-color)">}</span>
            <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span> <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"checkbox"</span> <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span> <span style="color:var(--syntax-text-color)">/></span>
            <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
          <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>

          <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Delete button */</span><span style="color:var(--syntax-string-color)">}</span>
          <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-name-color)">onClick</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleDelete</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>Delete<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">button</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)">))</span><span style="color:var(--syntax-string-color)">}</span>
    <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>

    <span style="color:var(--syntax-comment-color)">// ...</span>
  <span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

示例第一部分的最终代码

最终代码应如下所示:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">([]);</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">""</span><span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-comment-color)">// Retrieve all the items</span>
  <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/api/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
      <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">())</span>
      <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(({</span> <span style="color:var(--syntax-name-color)">items</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">));</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">]);</span>

  <span style="color:var(--syntax-comment-color)">// Adds a new item</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleAdd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">preventDefault</span><span style="color:var(--syntax-text-color)">();</span>

    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/api/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">POST</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
      <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">({</span> <span style="color:var(--syntax-name-color)">title</span> <span style="color:var(--syntax-text-color)">}),</span>
    <span style="color:var(--syntax-text-color)">}).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
      <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">""</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-comment-color)">// Mark an item as done</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`/api/grocery-list/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/done`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">PUT</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">}).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-comment-color)">// Deletes an item</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleDelete</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`/api/grocery-list/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">DELETE</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">}).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)"><></span>
      <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">form</span> <span style="color:var(--syntax-name-color)">onSubmit</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">handleAdd</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span>
          <span style="color:var(--syntax-name-color)">required</span>
          <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"text"</span>
          <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">target</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span>
          <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
        <span style="color:var(--syntax-text-color)">/></span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"submit"</span><span style="color:var(--syntax-text-color)">></span>Add<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">button</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">form</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">map</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">(</span>
          <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span> <span style="color:var(--syntax-name-color)">key</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
            <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
              <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span>
                <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"checkbox"</span>
                <span style="color:var(--syntax-name-color)">checked</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-string-color)">}</span>
                <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span>
              <span style="color:var(--syntax-text-color)">/></span>
              <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
            <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
            <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-name-color)">onClick</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleDelete</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>delete<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">button</span><span style="color:var(--syntax-text-color)">></span>
          <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-text-color)">))</span><span style="color:var(--syntax-string-color)">}</span>
      <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
    <span style="color:var(--syntax-text-color)"></></span>
  <span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

第一次重构:创建服务

现在我们已经准备就绪并且可以正常工作,让我们重构代码。

为了使代码更好,我们可以做的第一件事是为 API 调用创建服务。服务基本上是负责调用 API 的 JavaScript 函数。

这很有用,因为如果您需要在其他地方调用 API,您只需调用服务而不是复制粘贴整个fetch调用。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/services/grocery-list.js</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">basePath</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/api/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">getItems</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">());</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">createItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span>
  <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">POST</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">({</span> <span style="color:var(--syntax-name-color)">title</span> <span style="color:var(--syntax-text-color)">}),</span>
  <span style="color:var(--syntax-text-color)">});</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span>
  <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/done`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">PUT</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-text-color)">});</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">deleteItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span>
  <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">DELETE</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-text-color)">});</span>
</code></span></span>

请注意,服务正在返回一个 Promise,并且所有状态调用都已删除。我们还用常量替换了 API 端点的重复基本路径。

现在让我们fetch用新服务替换组件上的旧调用:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-comment-color)">// Importing the services</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">createItem</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">getItems</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">./services/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">// Service call</span>
    <span style="color:var(--syntax-name-color)">getItems</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(({</span> <span style="color:var(--syntax-name-color)">items</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">]);</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleAdd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">preventDefault</span><span style="color:var(--syntax-text-color)">();</span>

    <span style="color:var(--syntax-comment-color)">// Service call</span>
    <span style="color:var(--syntax-name-color)">createItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
      <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">""</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-comment-color)">// Service call</span>
    <span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleDelete</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">// Service call</span>
    <span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-comment-color)">// ...</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

这更具可读性和可测试性。您可以单独测试每个服务,而不是将组件作为一个整体进行测试。此外,更容易理解代码应该做什么,例如:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// Get the items, then set the items.</span>
<span style="color:var(--syntax-name-color)">getItems</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(({</span> <span style="color:var(--syntax-name-color)">items</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">});</span>
</code></span></span>

第二次重构:抽象 HTTP 调用

grocery-list服务严重依赖于 Fetch 库。如果我们决定将其更改为 Axios,则所有调用都应更改。另外,服务层不需要知道如何调用API,而只需要知道应该调用哪个API。

为了避免混淆这些职责,我喜欢创建一个 API 适配器。名称实际上并不重要 —此处的目标是在一个地方配置 API 的 HTTP 调用。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/adapters/api.js</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">basePath</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">/api</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">api</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">get</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">),</span>
  <span style="color:var(--syntax-name-color)">post</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">POST</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
      <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">body</span> <span style="color:var(--syntax-error-color)">&&</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">),</span>
    <span style="color:var(--syntax-text-color)">}),</span>
  <span style="color:var(--syntax-name-color)">put</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">PUT</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
      <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">body</span> <span style="color:var(--syntax-error-color)">&&</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">),</span>
    <span style="color:var(--syntax-text-color)">}),</span>
  <span style="color:var(--syntax-name-color)">delete</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">basePath</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">endpoint</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">DELETE</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">}),</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">api</span> <span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

这是整个应用程序中处理 HTTP 调用的唯一文件。其他需要调用API的文件只需要调用这些方法即可。

现在,如果您决定用 Axios 替换 Fetch,您只需更改这个文件就可以了。

在测试方面,现在可以在不依赖服务调用的情况下单独测试每个 API 方法。

谈到服务,让我们fetch用新的呼叫替换旧的呼叫api.

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/services/grocery-list</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">api</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">../adapters/api</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">resource</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">getItems</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">api</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">resource</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">());</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">createItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">api</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">post</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">resource</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">title</span> <span style="color:var(--syntax-text-color)">});</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">api</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">put</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">resource</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/done`</span><span style="color:var(--syntax-text-color)">);</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">deleteItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">api</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">delete</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">resource</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">/</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">itemId</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>

哇,干净多了!请注意,请求级别的一些职责不再存在,例如将 JSON 对象转换为字符串。这不是服务的责任,现在 API 层正在做这件事。

同样,代码变得更具可读性和可测试性。

第三次重构:创建挂钩

我们已经准备好服务和 API 层,现在让我们改进表示层,即 UI 组件。

这些组件当前正在直接调用服务。这工作正常,但保持状态和调用服务更像是应用程序的一个功能,而不是需要调用 API 的每个组件的责任。

我们要创建的第一个挂钩是useGetGroceryListItems(),它包含getItems()API 调用。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/hooks/grocery-list.js</span>

<span style="color:var(--syntax-comment-color)">// Default module import</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-name-color)">groceryListService</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">../services/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useGetGroceryListItems</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">([]);</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getItems</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(({</span> <span style="color:var(--syntax-name-color)">items</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">]);</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">refreshItems</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">refreshItems</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

请注意,我们基本上将组件之前的行为复制到了新的挂钩中。我们还需要创建refreshItems(),这样我们就可以在需要时更新数据,而不用再次直接调用服务。

我们还导入了服务模块以将其用作groceryListService.getItems(),而不是仅调用getItems(). 这是因为我们的钩子会有相似的函数名,所以为了避免冲突和提高可读性,整个服务模块被导入。

现在让我们为其他功能(创建、更新和删除)创建其余的挂钩。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/hooks/grocery-list.js</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useCreateGroceryListItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">createItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">createItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">createItem</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useMarkGroceryListItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useDeleteGroceryListItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">deleteItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">deleteItem</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

然后我们需要用组件中的钩子替换服务调用。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-comment-color)">// Hooks import</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">useGetGroceryListItems</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">useCreateGroceryListItem</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">useMarkGroceryListItemAsDone</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">useDeleteGroceryListItem</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">./hooks/grocery-list</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">refreshItems</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useGetGroceryListItems</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">createItem</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useCreateGroceryListItem</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useMarkGroceryListItemAsDone</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">deleteItem</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useDeleteGroceryListItem</span><span style="color:var(--syntax-text-color)">();</span>

  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">// Validation moved to hook and passing `item` instead of `item.id`</span>
    <span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">refreshItems</span><span style="color:var(--syntax-text-color)">());</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">handleDelete</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">// Passing `item` instead of `item.id`</span>
    <span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">refreshItems</span><span style="color:var(--syntax-text-color)">());</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-comment-color)">// ...</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

就是这样。现在应用程序正在利用挂钩,这很有用,因为如果您需要在其他组件中使用相同的功能,您只需调用它即可。

如果您使用状态管理解决方案,例如 Redux、Context API 或 Zustand,您可以在挂钩内部进行状态修改,而不是在组件级别调用它们。这有助于使事情变得更清晰,并且在职责之间得到很好的划分。

最后重构:添加加载状态

我们的应用程序运行良好,但在 API 请求和响应的等待期间没有向用户反馈。一种解决方案是为每个挂钩添加一个加载状态,以通知实际的 API 请求状态。

为每个钩子添加加载状态后,文件将如下所示:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/hooks/grocery-list.js</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useGetGroceryListItems</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Creating loading state</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">([]);</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span>

  <span style="color:var(--syntax-name-color)">useEffect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Adding loading state</span>
    <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getItems</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(({</span> <span style="color:var(--syntax-name-color)">items</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setItems</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">);</span>
      <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Removing loading state</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">]);</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">refreshItems</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">setRefresh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">refresh</span><span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">refreshItems</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useCreateGroceryListItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Creating loading state</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">createItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Adding loading state</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">createItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Removing loading state</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">createItem</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useMarkGroceryListItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Creating loading state</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Adding loading state</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Removing loading state</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useDeleteGroceryListItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Creating loading state</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">deleteItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Adding loading state</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">groceryListService</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">setIsLoading</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">false</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// Removing loading state</span>
    <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-text-color)">};</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

现在我们需要将页面的加载状态插入到每个钩子中:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/App.jsx</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">App</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-comment-color)">// Getting loading states and renaming to avoid conflicts</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">refreshItems</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">isFetchingItems</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useGetGroceryListItems</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">createItem</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">isCreatingItem</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useCreateGroceryListItem</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">isUpdatingItem</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useMarkGroceryListItemAsDone</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">deleteItem</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">isDeletingItem</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useDeleteGroceryListItem</span><span style="color:var(--syntax-text-color)">();</span>

  <span style="color:var(--syntax-comment-color)">// Read each loading state and convert them to a component-level value</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">isLoading</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">isFetchingItems</span> <span style="color:var(--syntax-error-color)">||</span> <span style="color:var(--syntax-name-color)">isCreatingItem</span> <span style="color:var(--syntax-error-color)">||</span> <span style="color:var(--syntax-name-color)">isUpdatingItem</span> <span style="color:var(--syntax-error-color)">||</span> <span style="color:var(--syntax-name-color)">isDeletingItem</span><span style="color:var(--syntax-text-color)">;</span>

  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)"><></span>
      <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">form</span> <span style="color:var(--syntax-name-color)">onSubmit</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">handleAdd</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span>
          <span style="color:var(--syntax-name-color)">required</span>
          <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"text"</span>
          <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">setTitle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">event</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">target</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span>
          <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
          <span style="color:var(--syntax-name-color)">disabled</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-string-color)">}</span> <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Loading State */</span><span style="color:var(--syntax-string-color)">}</span>
        <span style="color:var(--syntax-text-color)">/></span>
        <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"submit"</span> <span style="color:var(--syntax-name-color)">disabled</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span> <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Loading State */</span><span style="color:var(--syntax-string-color)">}</span>
          Add
        <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">button</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">form</span><span style="color:var(--syntax-text-color)">></span>
      <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">items</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">map</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">(</span>
          <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">li</span> <span style="color:var(--syntax-name-color)">key</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span>
            <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
              <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">input</span>
                <span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">"checkbox"</span>
                <span style="color:var(--syntax-name-color)">checked</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-string-color)">}</span>
                <span style="color:var(--syntax-name-color)">onChange</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleMarkAsDone</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span>
                <span style="color:var(--syntax-name-color)">disabled</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-string-color)">}</span> <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Loading State */</span><span style="color:var(--syntax-string-color)">}</span>
              <span style="color:var(--syntax-text-color)">/></span>
              <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">title</span><span style="color:var(--syntax-string-color)">}</span>
            <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">label</span><span style="color:var(--syntax-text-color)">></span>
            <span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-name-color)">onClick</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">handleDelete</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-string-color)">}</span> <span style="color:var(--syntax-name-color)">disabled</span><span style="color:var(--syntax-text-color)">=</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">isLoading</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)">></span> <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-comment-color)">/* Loading State */</span><span style="color:var(--syntax-string-color)">}</span>
              delete
            <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">button</span><span style="color:var(--syntax-text-color)">></span>
          <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">li</span><span style="color:var(--syntax-text-color)">></span>
        <span style="color:var(--syntax-text-color)">))</span><span style="color:var(--syntax-string-color)">}</span>
      <span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">ul</span><span style="color:var(--syntax-text-color)">></span>
    <span style="color:var(--syntax-text-color)"></></span>
  <span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

红利重构:创建实用程序

请注意,在useMarkGroceryListItemAsDone()挂钩中我们有一个逻辑来判断该项目是否应该更新:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/hooks/grocery-list.js</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// Don't call the service</span>
  <span style="color:var(--syntax-text-color)">}</span>

  <span style="color:var(--syntax-comment-color)">// Call the service and update the item</span>
</code></span></span>

这不是这个逻辑的理想位置,因为它可能在其他地方需要,迫使它重复,而且它是应用程序的业务逻辑,而不仅仅是这个钩子的特定逻辑。

一种可能的解决方案是创建一个 util 并在其中添加此逻辑,因此我们只调用挂钩中的函数:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// src/utils/grocery-list.js</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">shouldUpdateItem</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">isDone</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>

然后在挂钩中调用此实用程序:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">useMarkGroceryListItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-comment-color)">// ...</span>

  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">markItemAsDone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">// Calling the util</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-name-color)">shouldUpdateItem</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">item</span><span style="color:var(--syntax-text-color)">))</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-comment-color)">// ...</span>
</code></span></span>

现在钩子不依赖于任何与业务相关的逻辑:它们只是调用函数并返回它的值。

包起来

我们所做的所有重构都是为了提高代码质量,并使其对人类更具可读性。该代码起初可以运行,但不可扩展且不可测试。这些是优秀代码库的非常重要的特征。

我们基本上将单一职责原则应用于代码以使其变得更好。此代码可用作构建其他服务、连接外部 API、创建其他组件等的基础。

如前所述,您还可以在此处插入状态管理解决方案,并在我们创建的挂钩中管理应用程序的全局状态。

为了进一步改进代码,最好使用React Query来利用其缓存、重新获取和自动失效等功能。

就是这样!希望您今天学到了一些新东西,让您的编码之旅更加美好!

猜你喜欢

转载自blog.csdn.net/jascl/article/details/131304126