这篇文章主要介绍“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; /* * 延迟loading为true的时间 */ 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怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。