ahooks useRequest怎么使用
这篇文章主要介绍“ahooks useRequest怎么使用”,在日常操作中,相信很多人在ahooks useRequest怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ahooks useRequest怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
基础版(雏形)
先上代码:
useRequest.ts
interface UseRequestOptionsProps { initialData?: object; onSuccess?: (res: any) => void;}const useRequest = ( requestFn: ( initialData?: object | string | [], ) => Promise<SetStateAction<any>>, options: UseRequestOptionsProps,) => { const [data, setData] = useState<SetStateAction<any>>(null); const [loading, setLoading] = useState<boolean>(false); const [error, setError] = useState<string | null>(null); const { initialData, onSuccess } = options; useEffect(() => { setLoading(true); setError(null); setData(null); request(); }, [requestFn]); // useRequest业务逻辑 const request = async () => { try { const res = await requestFn(initialData); setData(res); // 请求成功响应回调 onSuccess && onSuccess(res); } catch (err) { err && setError(JSON.stringify(err)); } finally { setLoading(false); } }; return { data, loading, error };};export default useRequest;
使用
const { data, loading, error } = useRequest( queryCompensatoryOrderSituation, { initialData: { compensatoryId, } onSuccess: (res) => { console.log('success request!', res); }, },);
useRequest
对于请求函数的写法并无过多要求,只要是一个异步function
且返回一个promise
对象,即可传入useRequest
的第一个参数中,而第二个参数则是一系列的可选配置项,雏形版本我们暂时只支持onSuccess
。
手动触发
代码改造后:
useRequest.ts
interface UseRequestOptionsProps { manual?: boolean; initialData?: object; onSuccess?: (res: any) => void;}const useRequest = ( requestFn: ( initialData?: object | string | [], ) => Promise<SetStateAction<any>>, options: UseRequestOptionsProps,) => { const [data, setData] = useState<SetStateAction<any>>(null); const [loading, setLoading] = useState<boolean>(false); const [error, setError] = useState<string | null>(null); const { manual, initialData, onSuccess } = options; useEffect(() => { setLoading(true); setError(null); setData(null); !manual && request(); }, [manual]); // useRequest业务逻辑 const request = async () => { try { const res = await requestFn(initialData); setData(res); // 请求成功响应回调 onSuccess && onSuccess(res); } catch (err) { err && setError(JSON.stringify(err)); } finally { setLoading(false); } }; return { data, loading, error, request };};export default useRequest;
使用
const { data, loading, error, request } = useRequest( queryCompensatoryOrderSituation, { manual: true, initialData: { compensatoryId, }, onSuccess: (res) => { console.log('success request!', res); }, },);request();
手动执行的逻辑主要是根据manual
参数砍掉useRequest mount
阶段的渲染请求,把执行请求的能力暴露出去,在页面中去手动调用request()
来触发。
轮询与手动取消
代码改造后:
useRequest.ts
interface UseRequestOptionsProps { manual?: boolean; initialData?: object; pollingInterval?: number | null; onSuccess?: (res: any) => void;}const useRequest = ( requestFn: ( initialData?: object | string | [], ) => Promise<SetStateAction<any>>, options: UseRequestOptionsProps,) => { const [data, setData] = useState<SetStateAction<any>>(null); const [loading, setLoading] = useState<boolean>(false); const [error, setError] = useState<string | null>(null); const status = useRef<boolean>(false); const pollingIntervalTimer = useRef<NodeJS.Timer | null>(null); const { manual, initialData, pollingInterval, onSuccess } = options; useEffect(() => { setLoading(true); setError(null); setData(null); !manual && request(); }, [manual]); // useRequest业务逻辑 const request = async () => { try { !status.current && (status.current = true); if (pollingInterval && status.current) { pollingIntervalTimer.current = setTimeout(() => { status.current && request(); }, pollingInterval); } const res = await requestFn(initialData); setData(res); // 请求成功响应回调 onSuccess && onSuccess(res); } catch (err) { err && setError(JSON.stringify(err)); } finally { setLoading(false); } }; return { data, loading, error, request, cancel };};// 取消const cancel = () => { if (pollingIntervalTimer.current) { clearTimeout(pollingIntervalTimer.current); pollingIntervalTimer.current = null; status.current && (status.current = false); }};export default useRequest;
使用
const { data, loading, error, request, cancel } = useRequest( queryCompensatoryOrderSituation, { manual: true, initialData: { compensatoryId, }, pollingInterval: 1000, onSuccess: (res) => { console.log('success request!', res); }, },);request();...// 轮询到理想数据后cancel();
轮询的支持在hook中主要用到了timer setTimeout
的递归思路,同时给出一个status
状态值判断是否在轮询中,当调用端执行cancel()
,status
则为false
;当轮询开始,则status
为true
。
而cancel()
的能力 主要也是取消了timer
的递归请求逻辑,并且轮询的业务场景和manual: true
配合很多。
依赖请求(串型请求)
代码改造后:
useRequest.ts
interface UseRequestOptionsProps { manual?: boolean; initialData?: object; pollingInterval?: number | null; ready?: boolean; onSuccess?: (res: any) => void;}const useRequest = ( requestFn: ( initialData?: object | string | [], ) => Promise<SetStateAction<any>>, options: UseRequestOptionsProps,) => { const [data, setData] = useState<SetStateAction<any>>(null); const [loading, setLoading] = useState<boolean>(false); const [error, setError] = useState<string | null>(null); const status = useRef<boolean>(false); const pollingIntervalTimer = useRef<NodeJS.Timer | null>(null); const { manual, initialData, pollingInterval, ready = true, onSuccess, } = options; useEffect(() => { setLoading(true); setError(null); setData(null); !manual && ready && request(); }, [manual, ready]); // useRequest业务逻辑 const request = async () => { try { !status.current && (status.current = true); if (pollingInterval && status.current) { pollingIntervalTimer.current = setTimeout(() => { status.current && request(); }, pollingInterval); } const res = await requestFn(initialData); setData(res); // 请求成功响应回调 onSuccess && onSuccess(res); } catch (err) { err && setError(JSON.stringify(err)); } finally { setLoading(false); } }; return { data, loading, error, request, cancel };};// 取消const cancel = () => { if (pollingIntervalTimer.current) { clearTimeout(pollingIntervalTimer.current); pollingIntervalTimer.current = null; status.current && (status.current = false); }};export default useRequest;
使用
const [mountLoading, setMountLoading] = useState<boolean>(false);useEffect(() => { setMountLoading(true);}, [2000])const { data, loading, error, request, cancel } = useRequest( queryCompensatoryOrderSituation, { initialData: { compensatoryId, }, pollingInterval: 1000, ready: mountLoading, onSuccess: (res) => { console.log('success request!', res); }, },);
依赖请求的思路就是在hook
中加入一个ready
字段,也是在基于manual
一层的限制后又加了一层,来判断是否在hook
加载时是否做默认请求,而当option
中的ready
更新(为true)时,hook自动更新从而发起请求。
常用于页面中A请求完成后执行B请求,B请求的ready
字段依赖于A请求的data
/loading
字段。
防抖与节流
防抖和节流的实现比较简单,依赖于lodash
库,包装了一下request
函数的请求内容。
代码如下:
useRequest.ts
interface UseRequestOptionsProps { manual?: boolean; initialData?: object; pollingInterval?: number | null; ready?: boolean; debounceInterval?: number; throttleInterval?: number; onSuccess?: (res: any) => void;}const useRequest = ( requestFn: ( initialData?: object | string | [], ) => Promise<SetStateAction<any>>, options: UseRequestOptionsProps,) => { const [data, setData] = useState<SetStateAction<any>>(null); const [loading, setLoading] = useState<boolean>(false); const [error, setError] = useState<string | null>(null); const status = useRef<boolean>(false); const pollingIntervalTimer = useRef<NodeJS.Timer | null>(null); const { manual, initialData, pollingInterval, ready = true, debounceInterval, throttleInterval onSuccess, } = options; useEffect(() => { setLoading(true); setError(null); setData(null); !manual && ready && request(); }, [manual, ready]); // 请求 const request = () => { if (debounceInterval) { lodash.debounce(requestDoing, debounceInterval)(); } else if (throttleInterval) { lodash.throttle(requestDoing, throttleInterval)(); } else { requestDoing(); }};// useRequest业务逻辑const requestDoing = async () => { try { !status.current && (status.current = true); if (pollingInterval && status.current) { pollingIntervalTimer.current = setTimeout(() => { status.current && request(); }, pollingInterval); } const res = await requestFn(initialData); setData(res); // 请求成功响应回调 onSuccess && onSuccess(res); } catch (err) { err && setError(JSON.stringify(err)); } finally { setLoading(false); }};// 取消const cancel = () => { if (pollingIntervalTimer.current) { clearTimeout(pollingIntervalTimer.current); pollingIntervalTimer.current = null; status.current && (status.current = false); }};export default useRequest;
使用
const { data, loading, error, request, cancel } = useRequest( queryCompensatoryOrderSituation, { manual: true, initialData: { compensatoryId, }, debounceInterval: 1000, // 防抖 throttleInterval: 1000, // 节流 onSuccess: (res) => { console.log('success request!', res); }, },);for(let i = 0; i < 10000; i++) { request();}
在hook
中,通过lodash.debounce/lodash.throttle
来包装request
函数主体,通过option
中的判断来执行对应的包装体函数。
缓存与依赖更新
改造后的代码(最终代码)如下:
useRequest.ts
import { useState, useEffect, useRef, SetStateAction, useCallback,} from 'react';import lodash from 'lodash';interface UseRequestOptionsProps { manual?: boolean; initialData?: object; pollingInterval?: number | null; ready?: boolean; debounceInterval?: number; throttleInterval?: number; loadingDelay?: number; refreshDeps?: any[]; onSuccess?: (res: any) => void;}const useRequest = ( requestFn: ( initialData?: object | string | [], ) => Promise<SetStateAction<any>>, options: UseRequestOptionsProps,) => { const [data, setData] = useState<SetStateAction<any>>(null); const [loading, setLoading] = useState<boolean>(false); const [error, setError] = useState<string | null>(null); const status = useRef<boolean>(false); const pollingIntervalTimer = useRef<NodeJS.Timer | null>(null); const { manual, initialData, pollingInterval, ready = true, debounceInterval, throttleInterval, loadingDelay, refreshDeps, onSuccess, } = options; useEffect(() => { if (loadingDelay) { setTimeout(() => { status && setLoading(true); }, loadingDelay); } setError(null); setData(null); // 手动触发request !manual && ready && request(); }, [manual, ready, ...(Array.isArray(refreshDeps) ? refreshDeps : [])]); // 请求 const request = () => { if (debounceInterval) { lodash.debounce(requestDoing, debounceInterval)(); } else if (throttleInterval) { lodash.throttle(requestDoing, throttleInterval)(); } else { requestDoing(); } }; // useRequest业务逻辑 const requestDoing = async () => { try { !status.current && (status.current = true); if (pollingInterval && status.current) { pollingIntervalTimer.current = setTimeout(() => { status.current && request(); }, pollingInterval); } const res = await requestFn(initialData); setData(res); // 请求成功响应回调 onSuccess && onSuccess(res); } catch (err) { err && setError(JSON.stringify(err)); } finally { setLoading(false); } }; // 取消 const cancel = () => { if (pollingIntervalTimer.current) { clearTimeout(pollingIntervalTimer.current); pollingIntervalTimer.current = null; status.current && (status.current = false); } }; // 缓存 const cachedFetchData = useCallback(() => data, [data]); return { data, loading, error, request, cancel, cachedFetchData };};export default useRequest;
使用
const [mountLoading, setMountLoading] = useState<boolean>(false);const [updateLoading, setUpdateLoading] = useState<boolean>(false);setTimeout(() => { setMountLoading(true);}, 1000);setTimeout(() => { setUpdateLoading(true);}, 2000);const { data, loading, error, request, cancel, cachedFetchData } = useRequest( queryCompensatoryOrderSituation, { manual: true, initialData: { compensatoryId, }, debounceInterval: 1000, // 防抖 throttleInterval: 1000, // 节流 refreshDeps: [mountLoading, updateLoading], onSuccess: (res) => { console.log('success request!', res); }, },);
缓存的主体思路是在useRequest
中拿到第一次数据后通过useCallback
来透出data
依赖来保存,同时向外暴露一个cachedFetchData
来过渡data
从null
到请求到接口数据的过程。
依赖更新的思路则是在页面中给useRequest
一系列依赖状态一并加入在hook
的请求副作用中,监听到页面中依赖改变,则重新请求,具体实现则是refreshDeps
参数。
到此,关于“ahooks useRequest怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341