useRequest 是一个强大的异步数据管理的 Hooks,React 项目中的网络请求场景使用 useRequest 就够了。
useRequest 通过插件式组织代码,核心代码极其简单,并且可以很方便的扩展出更高级的功能。目前已有能力包括:
具体看官方文档
https://ahooks.js.org/zh-CN/hooks/use-request/index
useRequest
自定义 Hook,包含 run
方法:import { useState } from "react";
function useRequest(requestFunc) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
async function run(...args) {
setLoading(true);
setError(null);
setData(null);
try {
const result = await requestFunc(...args);
setData(result);
} catch (e) {
setError(e);
} finally {
setLoading(false);
}
}
return {
loading,
error,
data,
run,
};
}
useRequest
接受一个请求函数 requestFunc
作为参数,返回一个包含 loading
、error
、data
和 run
四个属性的对象。其中:
loading
表示当前请求是否正在加载;error
表示当前请求是否出错,如果出错则是一个 Error 对象;data
表示请求成功后返回的数据;run
是一个函数,用于执行请求函数并更新 loading
、error
和 data
状态。在 run
函数中,我们首先将 loading
状态设为 true
,将 error
和 data
状态设为 null
,然后执行请求函数并等待其返回结果。如果请求成功,则将返回的数据设为 data
状态;如果请求失败,则将错误信息设为 error
状态。最后,无论请求成功或失败,都将 loading
状态设为 false
。
使用示例:
import { useEffect } from "react";
import useRequest from "./useRequest";
function App() {
const { loading, error, data, run } = useRequest(fetchData);
useEffect(() => {
run();
}, []);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return <div>Data: {JSON.stringify(data)}</div>;
}
async function fetchData() {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = await response.json();
return data;
}
在上面的示例中,我们首先调用 useRequest
自定义 Hook,传入一个请求函数 fetchData
。然后在 useEffect
中调用 run
方法,执行初始请求。根据请求的状态,我们在页面中显示不同的内容:如果请求正在加载,显示 “Loading…”;如果请求出错,显示错误信息;如果请求成功,显示返回的数据。
下面是一个带有防抖节流功能的 useRequest
自定义 Hook:
const debounce = (fn, Wait) => {
let timer;
return function (...args) {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, Wait);
};
};
const throttle = (fn, Wait) => {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, Wait);
}
};
};
const _useRequest = (requestFn, options = {}) => {
const { debounceWait = 0, throttleWait = 0 } = options;
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
const run = useCallback(
(params) => {
setLoading(true);
setError(null);
const doRequest = () => {
requestFn(params)
.then((res) => setData(res))
.catch((e) => setError(e))
.finally(() => setLoading(false));
};
if (debounceWait > 0) {
const debounceRequest = debounce(doRequest, debounceWait);
debounceRequest();
} else if (throttleWait > 0) {
const throttleRequest = throttle(doRequest, throttleWait);
throttleRequest();
} else {
doRequest();
}
},
[requestFn, throttleWait, debounceWait]
);
return { loading, error, data, run };
};
这个 useRequest
自定义 Hook 接受两个参数:一个函数 request
,用于发起异步请求,以及一个可选的配置对象 options
,包含 debounceWait
和 throttleWait
两个属性,分别表示防抖和节流的等待时间。默认值为 0
,表示不启用防抖节流功能。
useRequest
返回一个包含 loading
、error
、data
和 run
四个属性的对象。其中,loading
表示异步请求是否正在加载,error
表示异步请求是否出错,data
表示异步请求返回的数据,run
是一个函数,用于发起异步请求。根据 debounceWait
和 throttleWait
的值,run
函数会启用防抖或节流功能,避免过于频繁的异步请求。