了解如何处理 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
- 其他组件中的每个 API 调用都需要一个新的本地
- 组件中直接调用请求库(Fetch)
- 例如,如果将库更改为 Axios,则每个组件都需要重构
- 这同样适用于端点,如果它发生变化,你需要在很多地方重构它
- 在展示组件中发出服务器级请求
- 组件旨在呈现数据,而不是处理获取逻辑
- 对每个组件、类和函数承担单一责任是一种很好的做法
- 不清楚请求将返回什么
- 您依靠端点名称来了解 API 将返回什么
有很多不同的方法可以解决这些问题。今天,我将向您展示我的想法和方法,以创建可靠且可扩展的文件夹和文件结构,您甚至可以在 Next.js 等框架上应用它或它背后的想法。
我们示例的场景
为了理解和结合所有概念,让我们逐步构建一个 Grocery List 应用程序。该应用程序将具有以下功能:
- 列出现有项目;
- 添加新项目;
- 除去项目;
- 将项目标记为已完成;
对于样式,我将使用TailwindCSS。为了模拟 API 请求,将使用Mirage JS ,这是一个非常易于使用且有用的 API 模拟库。要调用此 API,我们将使用Fetch。
所有示例都在我的GitHub上,所以请随意克隆存储库并使用它。README 文件中描述了如何运行它的详细信息。
最终结果将如下所示:
创建 API 端点
此应用程序将需要 4 个 API 端点:
GET /api/grocery-list
- 检索所有项目POST /api/grocery-list
- 创建一个新项目PUT /api/grocery-list/:id/done
- 将 id 等于 :id 的项目标记为完成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来利用其缓存、重新获取和自动失效等功能。
就是这样!希望您今天学到了一些新东西,让您的编码之旅更加美好!