在 React 中构建自定义钩子来获取数据
从后端获取数据是 Web 应用程序的关键部分之一。每个应用程序要想动态运行,都需要从服务器获取数据,然后将其显示在用户界面上。
我们使用 API 调用检索数据,并使用内置的 React hooks(例如 useState、useEffect 和 useReducer)将检索到的数据设置为状态变量。然后在组件中使用它来在视图中显示它。
在深入了解代码如何实现之前,让我们先了解一下什么是 React hooks 以及为什么要使用它。
什么是 React Hooks
React Hooks 最早是在 React 16.8 中引入的。它们是一些可以让你钩住 React 状态的函数。
React 提供的一些内置钩子是 useState、useEffect、useContext、useReducer、useRef、useCallback 和 useMemo。
为什么使用 React Hooks
使用 React Hooks 的主要优势之一是逻辑的可重用性。Hooks 可以在需要使用特定功能的多个组件中使用。
它还使代码更具可读性、效率和易于维护。
从服务器获取数据并在组件中更新的正常代码如下所示
export function Home(){
const [data,setData] = useState(null)
const [loading,setLoading] = useState(false)
const [error,setError] = useState(null)
useEffect(()=>{
(
async function(){
try{
setLoading(true)
const response = await axios.get('http:localhost:4000')
setData(response.data)
}
catch(err){
setError(err)
}finally{
setLoading(false)
}
}
)()
},[])
return(
{loading && <div>Loading...</div>}
{data && <div>{data}</div>
)
}
我们在 useEffect 钩子内编写逻辑来更新状态属性,如数据、加载和错误。
虽然这样写完全没问题,但是如果我们想在多个组件中做同样的事情,并且需要获取其他数据,该怎么办呢?
我们必须在所有这些组件中多次重写所有这些代码,这不是很高效并且难以管理。
在大型代码库中,最好遵循“不要重复自己”(DRY)原则,也就是说,最好编写一次代码并使其可重复使用,而不是在多个组件中一遍又一遍地编写它。
这就是自定义钩子的真正魔力所在。我们可以将代码写在一个单独的 js 文件中,然后所有需要从服务器获取数据的组件都可以使用 URL 来调用它。
这使得代码高效且易于维护。
就像 useState 和 useEffect 有其功能一样,我们通过组合它们来创建自定义钩子以实现特定的能力。
创建自定义 useFetch 钩子
我们首先创建一个名为 useFetch.js 的新 JavaScript 文件。
根据 React hooks 的约定,钩子的名称以 use 开头。
在文件中,创建一个以钩子名称命名的新函数。React 钩子和 React 组件的区别在于,钩子不返回 JSX。它只返回你想在组件中使用的状态变量或函数。
export function useFetch(){
}
要进行 API 调用,请使用 useEffect hook,因为它会在渲染时触发其内部的 API 调用函数。此处,API 调用是使用 Axios 进行的。
需要调用的 API Url 作为参数从组件传递给钩子。
import { useEffect } from "react"
import axios from axios
export function useFetch(url){
useEffect(()=>{
(
async function(){
const response = await axios.get(url)
}
)()
},[url])
}
通常,我们有 3 个状态变量,即使用 useState 创建的数据、错误和加载,分别用于存储响应数据、错误和加载,
如果接收到数据,我们将其设置为 data 变量。如果没有接收到,则将错误消息设置为 error 变量。
Loader 初始化为 false,调用 API 时会设置为 true,这样视图中就可以加载一个 loader 组件。
在 API 调用结束时,使用 finally 块将此加载器设置回 false。
import { useEffect, useState } from "react"
import axios from "axios"
export default function useFetch(url){
const [data,setData] = useState(null)
const [error,setError] = useState(null)
const [loading,setLoading] = useState(false)
useEffect(() => {
(
async function(){
try{
setLoading(true)
const response = await axios.get(url)
setData(response.data)
}catch(err){
setError(err)
}finally{
setLoading(false)
}
}
)()
}, [url])
return { data, error, loading }
}
我们要放入 useEffect 依赖数组的唯一依赖项是 Url,因为如果 Url 发生变化,我们就必须请求新数据。
这基本上就是 useEffect 的用法。现在我们将 hook 内部创建的状态以对象的形式返回。
在组件中使用自定义钩子
在组件内部,从其 JavaScript 文件导入 useFetch 钩子。导入后,使用 API Url 作为参数调用该钩子。
使用自定义 Hook 获取数据
export function Home(){
const {data,loading,error} = useFetch('https://localhost:4000')
if(error){
console.log(error)
}
return(
{loading && <div>Loading...</div>}
{data && <div>{data.map(item => <div>{item}</div>)}</div>}
)
}
除此之外,我们还可以通过让钩子返回可以从组件调用的任何函数来定制钩子。
例如,我们可以在钩子内部创建一个 refetch() 函数,当调用时重新获取 API。
该函数可以从钩子返回,并且可以从组件调用。
文章来源:https://dev.to/shaedrizwan/building-custom-hooks-in-react-to-fetch-data-4ig6