当前位置: 首页 > news >正文

中小企业网站建设客户需求调查问卷提高工作效率的方法不正确的是

中小企业网站建设客户需求调查问卷,提高工作效率的方法不正确的是,免费网站后台管理系统模板,广州装饰公司前言 最近业务没有之前紧张了,也是消失了一段时间,也总结了一些之前业务上的问题。 和同事沟通也是发现普通的async await 封装api在复杂业务场景下针对于请求的业务逻辑比较多,也是推荐我去学习一波ahooks,由于问题起源于请求…

前言

最近业务没有之前紧张了,也是消失了一段时间,也总结了一些之前业务上的问题。

和同事沟通也是发现普通的async + await + 封装api在复杂业务场景下针对于请求的业务逻辑比较多,也是推荐我去学习一波ahooks,由于问题起源于请求,因此作者也是直接从 useRequest 开始看起。

ahooks useRequest链接:

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

实现

话不多说,手写直接开始,参考几个比较常用的 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;当轮询开始,则statustrue

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,throttleIntervalonSuccess,} = 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来过渡datanull到请求到接口数据的过程。

依赖更新的思路则是在页面中给useRequest一系列依赖状态一并加入在hook的请求副作用中,监听到页面中依赖改变,则重新请求,具体实现则是refreshDeps参数。

结尾

花了一上午时间,一个简易版本的useRequest实现了,也是通过实现学习到了一些请求思路,在业务复杂的场景下也是很需要这类请求工具来让开发者的注意力从请求处理转移集中在业务逻辑中。

http://www.dinnco.com/news/37881.html

相关文章:

  • 绍兴柯桥哪里有做网站的百度指数属于行业趋势及人群
  • 南漳网站设计网站营销推广有哪些
  • 自己能注册网站吗网上电商怎么做
  • 西宁网站建设嘉荐君博l营销策划案ppt优秀案例
  • 网站请人做的 域名自己注册的 知道网站后台 怎么挂自己的服务器西安seo排名外包
  • 建设化妆品网站的成本seo站内优化
  • 假的建设银行网站google搜索首页
  • 企业宣传注册哪些论坛 网站好站长推荐产品
  • 网站分析报告社群营销是什么意思
  • 临沂最好的做网站公司网站自建
  • wordpress网站在哪里修改教育培训网站官网
  • 做web网站需要做网络通信吗浏览器正能量网站免费
  • 如何用ps做网站页面设计推广百度百科
  • 网页设计与制作模板免费排名优化哪家好
  • 做视频网站利润如何seo关键词有话要多少钱
  • 销售手机网站的后期安排seo推广培训费用
  • 合肥建设学校网站北京公司排名seo
  • 做网站好还是小程序好现在疫情怎么样了最新消息
  • 京东做代码的网站吗网络营销策划的主要特点
  • 网站建设saas附近学电脑培训班
  • 设计师电脑配置推荐2022杭州seo网络推广
  • 网站制作发票首页
  • 张家港百度网站推广天津seo排名扣费
  • 如何制作简单网页windows优化软件排行
  • 建设工程信息发布网站非国产手机浏览器
  • php动态网站开发代码软文广告500字
  • wap页面模板上海seo顾问推推蛙
  • 网站开发设计项目书重庆网站排名
  • 东营网站建设那家好网址大全2345
  • 江苏 做网站seo创业