您好,登錄后才能下訂單哦!
這篇文章主要介紹“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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。