React:创建用于获取数据的自定义钩子
从外部或内部 API 获取数据是 Web 应用程序的常见用例。React 函数式组件提供了不同的钩子来获取数据。本文将解释这些钩子,并帮助您了解何时使用它们。
上下文:获取用户的棋盘游戏收藏
在我的应用中,我想读取用户的棋盘游戏收藏并进行渲染。BoardGameGeek 平台提供了一个 JSON API。以下是示例:
curl https://bgg-json.azurewebsites.net/collection/newuser
[
{
"gameId": 180263,
"name": "The 7th Continent",
"image": "https://cf.geekdo-images.com/original/img/iQDBaRJ2LxJba_M7gPZj24eHwBc=/0x0/pic2648303.jpg",
"thumbnail": "https://cf.geekdo-images.com/thumb/img/zj6guxkAq2hrtEbLGFrIPCh4jv0=/fit-in/200x150/pic2648303.jpg",
[...]
}
]
要求
在开始编写代码之前,我喜欢花一些时间思考需求。这样,你就能有一个大致的框架和一个用于评估实现进度的清单。
让我们集思广益。获取数据是一个需要未知时间的过程。因此,我们应该给这个过程设置一个超时时间,并跟踪加载状态。获取数据可能会产生不同的错误:它可能完全失败,或者数据集可能与我们预期的不同,或者数据集本身存在错误。我们应该处理这些错误情况,并将错误视为获取过程的最终状态。
基本要求如下:
- R1 应该可以配置
url
为timeout
- R2 它应该返回 的状态
loading
,error
以及result
基本实现
基本要求可以通过以下代码来满足:
1 import React, {useState} from 'react';
2
3 function useFetchData(url, timeout) {
4 const [data, setData] = useState([]);
5 const [loading, setLoading] = useState(false);
6 const [error, setError] = useState(false);
7
8 return {data, loading, error};
9 }
- 在第 3 行中,我们定义了
useFetchData
函数,构造函数根据自定义钩子约定命名,并接收值url
和timeout
- 在第 4 至 6 行中,变量
data
、loading
和error
是用useState
钩子定义的 - 在第 8 行,返回所有状态变量
现在我们需要实现所需的功能。
获取数据
让我们编写获取数据的函数。
1 async function load() {
2 setLoading(true);
3 try {
4 const result = await axios.fetch(url, {timeout: timeout}).data;
5 setData(result);
6 } catch (e) {
7 setError(true);
8 }
9 setLoading(false);
10 }
- 在第 2 行中,我们设置了
loading = true
,并且仅在该函数的末尾将其设置为false
- 在第 3 行中,我们使用一个
try … catch
围绕实际 API 调用的块来捕获所有错误 - 在第 4 行中,我们使用axios 库向 URL 发出实际请求,并提供
timeout
值 - 在第 5-7 行中,如果获取数据成功,我们将设置
data
为result
,如果不成功,我们将设置error = true
通过这种逻辑,我们确保数据提取始终具有明确定义的状态:正在加载,或者如果没有加载,则会产生结果或错误。
重构
这个钩子满足了我们的要求 R1 和 R2。我们还能改进什么呢?每当组件被调用时,我们都应该将其状态重置为初始值。
function init() {
setData([]);
setLoading(true);
setLoading(false)
}
async function load() {
init();
...
}
如果我们在函数组件声明中直接调用该函数,会发生什么load
?该函数会改变组件的状态,从而触发重新渲染,load
并再次执行……
因此,需要从外部调用该函数 - 我们需要将其导出到使用此钩子的组件。
return {data, loading, error, load};
最终组件
这是最后一个组件:
import React, {useState} from 'react';
function useFetchData(url, timeout) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
function init() {
setData([]);
setLoading(true);
setLoading(false)
}
async function load() {
init();
setLoading(true);
try {
const result = await axios.fetch(url, {timeout: timeout}).data;
setData(result);
} catch (e) {
setError(true);
}
setLoading(false);
}
return {data, loading, error, load};
}
export default useFetchData;
结论
本文介绍了如何实现自定义数据获取钩子。我们了解到,组件始终需要保持一个精确的状态:正在加载,或者加载完成并返回结果或错误。当 API 被访问时,我们假设请求可能失败、数据未验证以及其他错误——所有这些都会被捕获并处理。最后,我们导出所有状态变量和加载函数,以便调用者拥有最大程度的控制权。
文章来源:https://dev.to/admantium/react-creating-a-custom-hook-for-fetching-data-168h