ym-userequest
English | 简体中文
介绍
接口的手动管理工具
安装
npm install ym-userequest
使用
- 手动执行
- 自动执行一次并带默认参数
- 取消响应
- 监听响应式数据并自动执行更新数据
- 延时 loading
- 修改 data 数据
- 轮询
- 允许请求
- 函数防抖
- 函数节流
- 缓存
- 错误重试
- requestTick
- 监听浏览器页面切换
- 获取指定的 useRequest 实例
- 自定义插件
- 中间件
- 全局配置
- 所有配置项
- 所有返回项
手动执行
import { useRequest } from 'ym-userequest';
const { data, params, loading, run, runAsync, refresh, refreshAsync, cancel } = useRequest(somePromise, {
manual: true,
});
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve('success');
});
};
run(); // 手动触发一次
// runAsync(); // 同 run , 但返回的是一个 promise
// refresh(); // 使用上次的参数重新请求
// refreshAsync(); // 同 refresh , 但返回的是一个 promise
// cancel(); // 取消请求
自动执行一次并带默认参数
// 多参数请求
const somePromise1 = (params1, params2) => {
return new Promise((resolve, reject) => {
resolve({ params1, params2 });
});
};
const { data, loading } = useRequest(somePromise1, {
defaultParams: ['params1', 'params2'],
});
// 单参数请求
const somePromise2 = (params1) => {
return new Promise((resolve, reject) => {
resolve({ params1 });
});
};
const { data, loading } = useRequest(somePromise2, {
defaultParams: 'params1', // or ['params1']
});
defaultParams 传入为数组时表示函数的多个参数,所以如果想要传入单个参数且参数本身为数组,应该使用 [array] 这样传参
取消响应
const request = () =>
fetch('https://httpbin.org/delay/3', {
method: 'POST',
body: JSON.stringify(params),
signal,
});
const { data, cancel } = useRequestI(request);
cancel();
调用 cancel 时只是忽略掉当前的请求,不会中断正在请求的请求。想要真正中断请求可以自行实现,参考下面的自定义 Fetch 请求取消插件
监听响应式数据并自动执行更新数据
const pages = reactive({
size: 1,
});
const somePromise = (number: number): Promise<any[]> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(new Array(number).fill(1));
}, 1000);
});
};
const refreshDepsParams = computed(() => pages.size);
const { data, refresh, loading } = useRequest(somePromise, {
defaultParams: pages.size,
refreshDeps: [() => pages.size], // 监听的依赖
// 可选,依赖变更后执行的参数,不传则在依赖变更后执行 refresh,
// 如果为函数会执行该函数并将返回值作为参数
refreshDepsParams: refreshDepsParams,
// 不想监听后立即请求,可以传递一个没有返回值的函数,该函数会被调用
// refreshDepsParams: () => {},
});
const onClick = () => {
pages.size++;
};
延时 loading
使用 loadingDelay 定义一个 loading 的延时时间,避免请求时间较短时出现 loading 闪烁
const somePromise = (params) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(params);
}, 300);
});
};
const { data, loading } = useRequest(somePromise, {
defaultParams: ['params1'],
loadingDelay: 1000, // 1s 内loading状态都不会改变
});
修改 data 数据
defaultData
因为 data 为 ref ,无法进行解构赋默认值,可通过 defaultData 设置默认值
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const { data, loading, mutate } = useRequest(somePromise, {
manual: true,
defaultData: 3, // return data:Ref<3>
// defaultData: shallowRef<3>, // return data:ShallowRef<3>
});
wrappedPromise
通过包装请求的方式来改变返回值,同时返回值的类型也对应改变
import { wrappedPromise } from 'ym-userequest';
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const { data, loading, mutate, requestTick } = useRequest(
wrappedPromise(somePromise, (result, params) => {
return { value: result };
}),
);
requestTick(() => {
console.log(data.value); // {value:1}
});
mutate
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const { data, loading, mutate } = useRequest(somePromise, { manual: true });
mutate(5555);
console.log(data.value); // 5555
const onChange = () => {
mutate((res) => {
return res + 1;
});
};
onChange();
console.log(data.value); // 2
轮询
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
// 每 3000 ms 进行一次请求
const { data, run, cancel } = useRequest(somePromise, {
pollingInterval: 3000,
});
const onRun = () => {
run(); // 继续轮询
};
const onCancel = () => {
cancel(); // 停止轮询
};
轮询错误重试
const errPromise = () => {
return new Promise((resolve, reject) => {
reject('error');
});
};
const { data, run, cancel } = useRequest(errPromise, {
pollingInterval: 3000,
pollingErrorRetryCount: 3, // 请求错误重试,将在三次轮询后不再轮询
});
轮询次数
在进行一次 cancel 后,轮询次数会被清空
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const { cancel, pollingCount } = useRequest(somePromise, {
pollingInterval: 100,
onFinally() {
if (pollingCount.value === 3) {
cancel();
}
},
});
允许请求
ready 参数控制本次请求是否被允许,若 ready 为 false ,该请求始终不会被允许
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const ready = ref(false);
const { data, run } = useRequest(somePromise, {
ready,
// or ready:()=> ready.value,
});
console.log(data.value); // null
ready.value = true;
run();
console.log(data.value); // 1
函数防抖
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const { data, run } = useRequest(somePromise, {
manual: true,
debounceWait: 2000,
debounceOptions: {
// 参数同 loadsh 的 debounce
leading: true,
trailing: false,
},
});
const onRun = () => {
run();
};
函数节流
const somePromise = () => {
return new Promise((resolve, reject) => {
resolve(1);
});
};
const { data, run } = useRequest(somePromise, {
manual: true,
throttleWait: 2000,
throttleOptions: {
// 参数同 loadsh 的 debounce
leading: true,
trailing: false,
},
});
const onRun = () => {
run();
};
缓存
设置了 cacheKey,组件在第二次加载时,会优先返回缓存的内容,然后在背后重新发起请求
import { useRequest, clearCache } from 'ym-userequest';
const somePromise = (value) => {
return new Promise((resolve, reject) => {
resolve(value);
});
};
const { data, run } = useRequest(somePromise, {
manual: true,
cacheKey: 'test',
cacheTime: 5000,
staleTime: -1,
// 自定义设置缓存
// setCache(cacheKey, data) {
// localStorage.setItem(cacheKey, JSON.stringify(data));
// },
// 自定义获取缓存
// getCache(cacheKey) {
// return JSON.parse(localStorage.getItem(cacheKey) || 'null');
// },
});
run(1); // 1
run(2); // 1
// 手动清除缓存 clearCache(params?:string[]|string)
// clearCache()
setTimeOut(() => {
run(2);
console.log(data.value); // 2
}, 5000);
错误重试
当请求失败后重新请求次数
const errorPromise = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('error');
}, 1000);
});
};
let count = 0;
const { data } = useRequest(errorPromise, {
retryCount: 3,
// retryInterval:1000,
onError() {
count += 1;
console.log(count);
},
});
// count:1
// count:2
// count:3
// count:4
requestTick
等待请求完成后的操作回调
const getData = (value = 1, time = 1000): Promise<number> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(value);
}, time);
});
};
const { data, run: run1, requestTick } = useRequest(() => getData(3), { manual: true });
const { run: run2 } = useRequest(getData, { manual: true });
const runAll = async () => {
run1();
run2();
console.log(data.value); // undefined
await requestTick(() => {
console.log(data.value); // 3
});
console.log(data.value); // 3
};
runAll();
监听浏览器页面切换
useRequest(getData, {
// 在浏览器页面重新显示时,重新发起请求
refreshOnWindowFocus: true,
// 间隔1000ms内不重新请求
focusTimespan: 1000,
// 离开浏览器页面时,取消请求
cancelOnWindowBlur: true,
});
获取指定的 useRequest 实例
可以运用在不同的组件,获取指定的 useRequest 实例
import { useRequest, getRequest } from 'ym-request';
const instance1 = useRequest(getData, {
id: 'getData',
manual: true,
});
instance1.run(2);
const instance2 = getRequest('getData');
console.log(instance1.data, instance2.data); // 2,2
instance2.run(3);
console.log(instance1.data, instance2.data); // 3,3
自定义插件
在 instance 中可以获取所有返回项
在 options 中可以获取所有配置项
插件返回对象中,onBefore 中返回 returnNow 为 true 时,将不再发起请求,返回 returnData 将作为 data 数据返回
onInit 可以用来改写请求
onSuccess 等其他函数对应请求的各个时机
内置插件 useReadyPlugin
import { definePlugins, TypeChecker, Plugin } from 'ym-userequest';
import { Ref, unref } from 'vue';
const useReadyPlugin: Plugin<any, any[]> = (instance, options) => {
const { ready = true } = options;
return {
onBefore() {
const _ready = TypeChecker.isFunction(ready) ? (ready as () => boolean | Ref<boolean>)() : ready;
if (!unref(_ready)) {
instance.loading.value = false;
return {
returnNow: true,
// returnData: instance.data.value,
};
}
},
// 所有的返回签名,对应 useRequest 的回调
// onBefore: (params: P) => onBeforePlugin | void;
// onInit: (service: (...args: P) => Promise<R>) => { servicePromise: Promise<R> },
// onSuccess(data: R, params: P): void,
// onError(error: Error, params: P): void,
// onFinally(params: P, data: R, error: Error): void,
// onCancel(): void,
// onMutate(data: R): void,
};
};
// 注册
definePlugins([useReadyPlugin]);
自定义 Fetch 请求取消插件
插件
// useFetchCancelPlugin.ts
import { type Plugin } from 'ym-userequest';
export const useFetchCancelPlugin: Plugin<any, any[]> = (instance, { controller }) => {
if (!controller) {
return {};
}
let currentController = new AbortController();
return {
onBefore() {
if (currentController.signal.aborted) {
currentController = new AbortController();
}
},
onInit(service) {
return {
servicePromise: service(...instance.params.value, currentController.signal),
};
},
onCancel() {
currentController.abort();
},
};
};
注册
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { useFetchCancelPlugin } from './useFetchCancelPlugin';
import { definePlugins } from 'ym-userequest';
definePlugins([useFetchCancelPlugin]);
const app = createApp(App);
app.mount('#app');
使用
import { useRequest } from 'ym-userequest';
const request = (params: any, signal?: AbortSignal) =>
fetch('https://httpbin.org/delay/3', {
method: 'POST',
body: JSON.stringify(params),
signal,
});
const { data, loading, status, cancel, run } = useRequest(request, {
manual: true,
controller: true,
onCancel() {
console.log('onCancel');
},
});
run(123);
setTimeout(() => {
cancel();
}, 1000);
中间件
const logs: string[] = [];
const logger1 = (useRequestNext: any) => {
return (service: any, options: any, plugins: any) => {
logs.push('logger1 enter');
const extendedService = (...args: any[]) => {
logs.push('logger1 service');
return service(...args);
};
const next = useRequestNext(extendedService, options, plugins);
logs.push('logger1 exit');
return next;
};
};
const logger2 = (useRequestNext: any) => {
return (service: any, options: any, plugins: any) => {
logs.push('logger2 enter');
const extendedService = (...args: any[]) => {
logs.push('logger2 service');
return service(...args);
};
const next = useRequestNext(extendedService, options, plugins);
logs.push('logger2 exit');
return next;
};
};
useRequest(getData, {
manual: true,
use: [logger1, logger2],
});
run();
// logs: ['logger1 enter', 'logger2 enter', 'logger2 exit', 'logger1 exit', 'logger2 service', 'logger1 service'];
全局配置
在组件中使用时该组件及其子组件的 useRequest 的 options 默认为 useRequestConfig 传入的 options
useRequestConfig({ manual: true });
所有配置项
{
// 是否手动发起请求,默认 false ,会在初始化后自动执行一次 run
manual?: boolean;
// 设置默认 data,也可用于指定 data 为 ShallowRef 或 Ref
// 如果传入值为非响应式,将被转化为 ref
defaultData?: R | Ref<R>;
// 当 manual 为 false 时,自动执行的默认参数
defaultParams?: Params<P>;
// 监听依赖
refreshDeps?: WatchSource<any>[] | WatchSource<any>;
// 依赖变更后的执行参数,若为函数会执行该函数,有返回值则会将返回值作为参数发起一次请求
refreshDepsParams?: Params<P> | ((value: P, oldValue: P) => void | Params<P>);
// 请求延时
loadingDelay?: number;
// 轮询
pollingInterval?: Ref<number> | number;
// 轮询错误重试
pollingErrorRetryCount?: number;
// 错误重试次数
retryCount?:number;
// 重试时间间隔
// 如果不设置,默认采用简易的指数退避算法,取 1000 * 2 ** retryCount,
// 也就是第一次重试等待 2s,第二次重试等待 4s,以此类推,如果大于 30s,则取 30s
retryInterval?:number;
// 是否允许请求(变更时不会触发自动请求)
ready?: (() => Ref<boolean> | boolean) | (Ref<boolean> | boolean);
// 防抖等待时间
debounceWait?: number;
// 防抖函数属性
debounceOptions?: {
// 是否在延迟开始前执行
leading?: boolean;
// 是否在延迟开始后执行
trailing?: boolean;
// 允许被延迟的最大值
maxWait?: number;
};
// 节流等待时间
throttleWait?: number;
// 节流函数属性
throttleOptions?: {
// 是否在延迟开始前执行
leading?: boolean;
// 是否在延迟开始后执行
trailing?: boolean;
};
// 缓存的唯一标识
cacheKey?: string | ((params?: P) => string);
// 缓存时间,默认: 5 * 60 * 1000
// 超出缓存时间会清除对应缓存
// 另外需要注意的是,当缓存失效时,无论 staleTime 是否存在都会重新请求
cacheTime?: number;
// 缓存数据保持新鲜时间(什么时候会重新发送请求更新缓存),默认 0,若为-1表示始终不再发送请求
// 即在新鲜时间内都直接获取缓存中的数据
staleTime?: number;
// 自定义获取缓存
getCache?: (cacheKey: string) => CacheData;
// 自定义设置缓存
setCache?: (cacheKey: string, cacheData: CacheData) => void;
// 在浏览器页面重新显示时,是否重新发起请求
refreshOnWindowFocus?: Ref<boolean> | boolean;
// 重新请求间隔,单位为毫秒,默认5000
focusTimespan?: Ref<number> | number;
// 离开浏览器页面时,是否取消请求
cancelOnWindowBlur?: Ref<boolean> | boolean;
// 获取缓存时回调
onCache?: (response: R) => void;
// 请求前回调
onBefore?: (params: P) => void;
// 每次请求被执行时回调,可以在该回调中获取每次请求的响应
onRequest?: ({ params, response, error, abort }: { params: P; response: R; error: any; abort: boolean }) => void;
// 成功回调(在该回调之后 data 被重新赋值)
onSuccess?: (response: R, params: P) => MaybePromise<void | R>;
// 失败回调
onError?: (err: any, params: P) => void;
// 接口完成回调
onFinally?: () => void;
// 忽略当前 Promise 时执行回调
onCancel?:()=>void;
// 中间件
use?: UseRequestMiddleware<R, P>[];
}
所有返回项
{
// 返回请求执行成功后的返回的数据
data: Ref<R>;
// 返回请求的执行状态
loading: Ref<boolean>;
// 返回请求失败的错误信息
error?: Ref<any>;
// 返回本次请求的参数
params?: Ref<P>;
// 进行轮询时累计轮询次数
pollingCount:Ref<number>
// 手动执行请求(返回promise)
runAsync: (...arg: P) => Promise<R>;
// 手动执行请求
run: (...arg: P) => void;
// 忽略当前 Promise 的响应
cancel: () => void;
// 手动刷新请求
refresh: () => void;
// 手动刷新请求(返回promise)
refreshAsync: () => Promise<R>;
// 修改返回的data数据
mutate: (newData: R) => void | (arg: (oldData: R) => R) => void;
// data 处理进程,默认undfined,表示未被请求过
status: Ref<'pending' | 'settled'>;
// 等待接口完成
requestTick: (callback?: (context: { params: P; data: R }) => void) => Promise<{ params: P; data: R }>;
}
Related Packages
A Vue3 asynchronous request processing library, designed to simplify your asynch...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.14.0 | ^3.2.47 | ||
| 1.13.7 | ^3.2.47 | ||
| 1.13.6 | ^3.2.47 | ||
| 1.13.5 | ^3.2.47 | ||
| 1.13.4 | ^3.2.47 | ||
| 1.13.3 | ^3.2.47 | ||
| 1.13.2 | ^3.2.47 | ||
| 1.13.1 | ^3.2.47 | ||
| 1.13.0 | ^3.2.47 | ||
| 1.12.10 | ^3.2.47 | ||
| 1.12.9 | ^3.2.47 | ||
| 1.12.8 | ^3.2.47 | ||
| 1.12.7 | ^3.2.47 | ||
| 1.12.6 | ^3.2.47 | ||
| 1.12.5 | ^3.2.47 | ||
| 1.12.4 | ^3.2.47 | ||
| 1.12.3 | ^3.2.47 | ||
| 1.12.2 | ^3.2.47 | ||
| 1.12.1 | ^3.2.47 | ||
| 1.12.0 | ^3.2.47 | ||
| 1.11.2 | ^3.2.47 | ||
| 1.11.1 | ^3.2.47 | ||
| 1.11.0 | ^3.2.47 | ||
| 1.10.0 | ^3.2.47 | ||
| 1.9.0 | ^3.2.47 | ||
| 1.8.0 | ^3.2.47 | ||
| 1.7.0 | ^3.2.47 | ||
| 1.6.0 | ^3.3.4 | ||
| 1.5.2 | ^3.3.4 | ||
| 1.5.1 | ^3.3.4 |
Showing the latest 30 of 42. See every release on npm
Pre-releases (3)
| Version | Released | Vue | License |
|---|---|---|---|
| 1.14.1-beta.0 | ^2.0.0 || | ||
| 1.13.8-beta.1 | ^3.2.47 | ||
| 1.13.8-beta.0 | ^3.2.47 |