中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

中小企業(yè)網(wǎng)站建設(shè)客戶(hù)需求調(diào)查問(wèn)卷seo關(guān)鍵詞優(yōu)化公司哪家好

中小企業(yè)網(wǎng)站建設(shè)客戶(hù)需求調(diào)查問(wèn)卷,seo關(guān)鍵詞優(yōu)化公司哪家好,學(xué)做甜品的網(wǎng)站,怎么用iapp做網(wǎng)站軟件前言 最近業(yè)務(wù)沒(méi)有之前緊張了,也是消失了一段時(shí)間,也總結(jié)了一些之前業(yè)務(wù)上的問(wèn)題。 和同事溝通也是發(fā)現(xiàn)普通的async await 封裝api在復(fù)雜業(yè)務(wù)場(chǎng)景下針對(duì)于請(qǐng)求的業(yè)務(wù)邏輯比較多,也是推薦我去學(xué)習(xí)一波ahooks,由于問(wèn)題起源于請(qǐng)求…

前言

最近業(yè)務(wù)沒(méi)有之前緊張了,也是消失了一段時(shí)間,也總結(jié)了一些之前業(yè)務(wù)上的問(wèn)題。

和同事溝通也是發(fā)現(xiàn)普通的async + await + 封裝api在復(fù)雜業(yè)務(wù)場(chǎng)景下針對(duì)于請(qǐng)求的業(yè)務(wù)邏輯比較多,也是推薦我去學(xué)習(xí)一波ahooks,由于問(wèn)題起源于請(qǐng)求,因此作者也是直接從 useRequest 開(kāi)始看起。

ahooks useRequest鏈接:

https://ahooks-v2.js.org/zh-CN/hooks/async/

實(shí)現(xiàn)

話(huà)不多說(shuō),手寫(xiě)直接開(kāi)始,參考幾個(gè)比較常用的 useRequest 能力來(lái)一個(gè)個(gè)實(shí)現(xiàn)吧。

基礎(chǔ)版(雛形)

先上代碼:

useRequest.ts

interface UseRequestOptionsProps {/** 請(qǐng)求參數(shù)*/initialData?: object;/** 請(qǐng)求成功回調(diào)*/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業(yè)務(wù)邏輯const request = async () => {try {const res = await requestFn(initialData);setData(res);// 請(qǐng)求成功響應(yīng)回調(diào)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 對(duì)于請(qǐng)求函數(shù)的寫(xiě)法并無(wú)過(guò)多要求,只要是一個(gè)異步function且返回一個(gè)promise對(duì)象,即可傳入useRequest的第一個(gè)參數(shù)中,而第二個(gè)參數(shù)則是一系列的可選配置項(xiàng),雛形版本我們暫時(shí)只支持onSuccess

手動(dòng)觸發(fā)

代碼改造后:

useRequest.ts

interface UseRequestOptionsProps {/** 手動(dòng)開(kāi)啟*/manual?: boolean;/** 請(qǐng)求參數(shù)*/initialData?: object;/** 請(qǐng)求成功回調(diào)*/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業(yè)務(wù)邏輯const request = async () => {try {const res = await requestFn(initialData);setData(res);// 請(qǐng)求成功響應(yīng)回調(diào)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();

手動(dòng)執(zhí)行的邏輯主要是根據(jù)manual參數(shù)砍掉useRequest mount階段的渲染請(qǐng)求,把執(zhí)行請(qǐng)求的能力暴露出去,在頁(yè)面中去手動(dòng)調(diào)用request()來(lái)觸發(fā)。

輪詢(xún)與手動(dòng)取消

代碼改造后:

useRequest.ts

interface UseRequestOptionsProps {/** 手動(dòng)開(kāi)啟*/manual?: boolean;/** 請(qǐng)求參數(shù)*/initialData?: object;/** 輪詢(xún)*/pollingInterval?: number | null;/** 請(qǐng)求成功回調(diào)*/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業(yè)務(wù)邏輯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);// 請(qǐng)求成功響應(yīng)回調(diào)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();...
// 輪詢(xún)到理想數(shù)據(jù)后
cancel();

輪詢(xún)的支持在hook中主要用到了timer setTimeout的遞歸思路,同時(shí)給出一個(gè)status狀態(tài)值判斷是否在輪詢(xún)中,當(dāng)調(diào)用端執(zhí)行cancel()status則為false;當(dāng)輪詢(xún)開(kāi)始,則statustrue。

cancel()的能力主要也是取消了timer的遞歸請(qǐng)求邏輯,并且輪詢(xún)的業(yè)務(wù)場(chǎng)景和manual: true配合很多。

依賴(lài)請(qǐng)求(串型請(qǐng)求)

代碼改造后:

useRequest.ts

interface UseRequestOptionsProps {/** 手動(dòng)開(kāi)啟*/manual?: boolean;/** 請(qǐng)求參數(shù)*/initialData?: object;/** 輪詢(xún)*/pollingInterval?: number | null;/** 準(zhǔn)備,用于依賴(lài)請(qǐng)求*/ready?: boolean;/** 請(qǐng)求成功回調(diào)*/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業(yè)務(wù)邏輯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);// 請(qǐng)求成功響應(yīng)回調(diào)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);},},
);

依賴(lài)請(qǐng)求的思路就是在hook中加入一個(gè)ready字段,也是在基于manual一層的限制后又加了一層,來(lái)判斷是否在hook加載時(shí)是否做默認(rèn)請(qǐng)求,而當(dāng)option中的ready更新(為true)時(shí),hook自動(dòng)更新從而發(fā)起請(qǐng)求。

常用于頁(yè)面中A請(qǐng)求完成后執(zhí)行B請(qǐng)求,B請(qǐng)求的ready字段依賴(lài)于A(yíng)請(qǐng)求的data/loading字段。

防抖與節(jié)流

防抖和節(jié)流的實(shí)現(xiàn)比較簡(jiǎn)單,依賴(lài)于lodash庫(kù),包裝了一下request函數(shù)的請(qǐng)求內(nèi)容。

代碼如下:

useRequest.ts

interface UseRequestOptionsProps {/** 手動(dòng)開(kāi)啟*/manual?: boolean;/** 請(qǐng)求參數(shù)*/initialData?: object;/** 輪詢(xún)*/pollingInterval?: number | null;/** 準(zhǔn)備,用于依賴(lài)請(qǐng)求*/ready?: boolean;/** 防抖*/debounceInterval?: number;/** 節(jié)流*/throttleInterval?: number;/** 請(qǐng)求成功回調(diào)*/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,throttleIntervalonSuccess,} = options;useEffect(() => {setLoading(true);setError(null);setData(null);!manual && ready && request();}, [manual, ready]);//  請(qǐng)求const request = () => {if (debounceInterval) {lodash.debounce(requestDoing, debounceInterval)();} else if (throttleInterval) {lodash.throttle(requestDoing, throttleInterval)();} else {requestDoing();}
};// useRequest業(yè)務(wù)邏輯
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);// 請(qǐng)求成功響應(yīng)回調(diào)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,     // 節(jié)流onSuccess: (res) => {console.log('success request!', res);},},
);for(let i = 0; i < 10000; i++) {request();
}

hook中,通過(guò)lodash.debounce/lodash.throttle來(lái)包裝request函數(shù)主體,通過(guò)option中的判斷來(lái)執(zhí)行對(duì)應(yīng)的包裝體函數(shù)。

緩存與依賴(lài)更新

改造后的代碼(最終代碼)如下:

useRequest.ts

import {useState,useEffect,useRef,SetStateAction,useCallback,
} from 'react';
import lodash from 'lodash';interface UseRequestOptionsProps {/** 手動(dòng)開(kāi)啟*/manual?: boolean;/** 請(qǐng)求參數(shù)*/initialData?: object;/** 輪詢(xún)*/pollingInterval?: number | null;/** 準(zhǔn)備,用于依賴(lài)請(qǐng)求*/ready?: boolean;/** 防抖*/debounceInterval?: number;/** 節(jié)流*/throttleInterval?: number;/** 延遲loading為true的時(shí)間*/loadingDelay?: number;/** 依賴(lài)*/refreshDeps?: any[];/** 請(qǐng)求成功回調(diào)*/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);// 手動(dòng)觸發(fā)request!manual && ready && request();}, [manual, ready, ...(Array.isArray(refreshDeps) ? refreshDeps : [])]);//  請(qǐng)求const request = () => {if (debounceInterval) {lodash.debounce(requestDoing, debounceInterval)();} else if (throttleInterval) {lodash.throttle(requestDoing, throttleInterval)();} else {requestDoing();}};// useRequest業(yè)務(wù)邏輯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);// 請(qǐng)求成功響應(yīng)回調(diào)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,     // 節(jié)流refreshDeps: [mountLoading, updateLoading],onSuccess: (res) => {console.log('success request!', res);},},
);

緩存的主體思路是在useRequest中拿到第一次數(shù)據(jù)后通過(guò)useCallback來(lái)透出data依賴(lài)來(lái)保存,同時(shí)向外暴露一個(gè)cachedFetchData來(lái)過(guò)渡datanull到請(qǐng)求到接口數(shù)據(jù)的過(guò)程。

依賴(lài)更新的思路則是在頁(yè)面中給useRequest一系列依賴(lài)狀態(tài)一并加入在hook的請(qǐng)求副作用中,監(jiān)聽(tīng)到頁(yè)面中依賴(lài)改變,則重新請(qǐng)求,具體實(shí)現(xiàn)則是refreshDeps參數(shù)。

結(jié)尾

花了一上午時(shí)間,一個(gè)簡(jiǎn)易版本的useRequest實(shí)現(xiàn)了,也是通過(guò)實(shí)現(xiàn)學(xué)習(xí)到了一些請(qǐng)求思路,在業(yè)務(wù)復(fù)雜的場(chǎng)景下也是很需要這類(lèi)請(qǐng)求工具來(lái)讓開(kāi)發(fā)者的注意力從請(qǐng)求處理轉(zhuǎn)移集中在業(yè)務(wù)邏輯中。

http://www.risenshineclean.com/news/22526.html

相關(guān)文章:

  • 遼寧省建設(shè)廳證書(shū)查詢(xún)網(wǎng)站百度關(guān)鍵詞搜索量排名
  • 江油市建設(shè)局網(wǎng)站溫州網(wǎng)站快速排名
  • wordpress hello dolly杭州百度優(yōu)化
  • 外貿(mào)網(wǎng)站建設(shè)海外推廣網(wǎng)絡(luò)銷(xiāo)售真惡心
  • 輕創(chuàng)靈感網(wǎng)站百度自動(dòng)點(diǎn)擊器怎么用
  • 外貿(mào)seo搜索優(yōu)化湖南seo快速排名
  • 北京好的網(wǎng)站制作小說(shuō)榜單首頁(yè)百度搜索風(fēng)云榜
  • 深圳網(wǎng)站建設(shè)服務(wù)商萬(wàn)創(chuàng)網(wǎng)網(wǎng)站代運(yùn)營(yíng)推廣
  • 網(wǎng)站建設(shè) 圖標(biāo)百度快速收錄技術(shù)
  • 西安網(wǎng)站維護(hù)深圳網(wǎng)站建設(shè)開(kāi)發(fā)公司
  • wordpress站點(diǎn)版權(quán)設(shè)置拉新推廣賺錢(qián)的app
  • 合肥網(wǎng)站搭建鄭州網(wǎng)絡(luò)推廣代理顧問(wèn)
  • 城鄉(xiāng)建設(shè)官網(wǎng)說(shuō)說(shuō)seo論壇
  • 網(wǎng)站右下角彈窗代碼網(wǎng)絡(luò)營(yíng)銷(xiāo)方式都有哪些
  • 個(gè)人的網(wǎng)站免費(fèi)網(wǎng)絡(luò)推廣
  • 巴里坤網(wǎng)站建設(shè)seo快速排名培訓(xùn)
  • 各大網(wǎng)站投稿郵箱杭州關(guān)鍵詞優(yōu)化服務(wù)
  • 南京哪家公司做企業(yè)網(wǎng)站 做得比較好吸引客流的25個(gè)技巧
  • 網(wǎng)站設(shè)計(jì)英文網(wǎng)絡(luò)廣告營(yíng)銷(xiāo)案例分析
  • 北京做網(wǎng)站公司推薦seo工具軟件
  • 杭州品牌網(wǎng)站設(shè)計(jì)seo優(yōu)化什么意思
  • 廣州網(wǎng)站建站青島百度快速優(yōu)化排名
  • 西寧做網(wǎng)站ci君博卻上無(wú)錫百度競(jìng)價(jià)推廣
  • 企業(yè)建站業(yè)務(wù)還能做嗎沈陽(yáng)seo合作
  • 模具 東莞網(wǎng)站建設(shè)長(zhǎng)沙網(wǎng)絡(luò)推廣外包費(fèi)用
  • 手機(jī) 網(wǎng)站 微信 源碼河南網(wǎng)站seo
  • 龍巖網(wǎng)站制作長(zhǎng)沙網(wǎng)站快速排名提升
  • 只做日本的網(wǎng)站網(wǎng)站域名購(gòu)買(mǎi)
  • 茄子河區(qū)網(wǎng)站建設(shè)自查報(bào)告常用的網(wǎng)絡(luò)推廣方式有哪些
  • 網(wǎng)站如何做用戶(hù)的實(shí)名認(rèn)證開(kāi)發(fā)一個(gè)網(wǎng)站的步驟流程