ahooks useRequest 源码解读
ahooks useRequest 源码解读
数据可视化,公众号@开源探月,GitHub@kf-liu
收录于 · 前端开源挖宝贝啦
7 人赞同了该文章
展开目录
⚠️预警: 万字长文, 收藏先~
插件来啦!!!
https://zhuanlan.zhihu.com/p/548160867
20220803更新:
本文GitHub地址, 欢迎✨Star:
useRequest作为ahooks中最重要的成员之一, 在实际开发中的使用频率还是很高的, 功能也很全面, 值得一读.
文件结构
useRequest核心代码位于项目packages/hooks/src/useRequest/src/ , 其下文件目录:
src
├── Fetch.ts
├── types.ts
├── useRequest.ts
├── useRequestImplement.ts
├── plugins
│ ├── useAutoRunPlugin.ts
│ ├── useCachePlugin.ts
│ ├── useDebouncePlugin.ts
│ ├── useLoadingDelayPlugin.ts
│ ├── usePollingPlugin.ts
│ ├── useRefreshOnWindowFocusPlugin.ts
│ ├── useRetryPlugin.ts
│ └── useThrottlePlugin.ts
└── utils
├── cache.ts
├── cachePromise.ts
├── cacheSubscribe.ts
├── isDocumentVisible.ts
├── isOnline.ts
├── limit.ts
├── subscribeFocus.ts
└── subscribeReVisible.ts
收口处 · useRequest.ts
自顶向下的看, 自然是从useRequest.ts入手, 但显然, 这只是一个隐藏了核心逻辑的规范化收口文件 ⬇️
源码
import useAutoRunPlugin from './plugins/useAutoRunPlugin';
import useCachePlugin from './plugins/useCachePlugin';
import useDebouncePlugin from './plugins/useDebouncePlugin';
import useLoadingDelayPlugin from './plugins/useLoadingDelayPlugin';
import usePollingPlugin from './plugins/usePollingPlugin';
import useRefreshOnWindowFocusPlugin from './plugins/useRefreshOnWindowFocusPlugin';
import useRetryPlugin from './plugins/useRetryPlugin';
import useThrottlePlugin from './plugins/useThrottlePlugin';
import type { Options, Plugin, Service } from './types';
import useRequestImplement from './useRequestImplement';
function useRequest<TData, TParams extends any[]>(
service: Service<TData, TParams>,
options?: Options<TData, TParams>,
plugins?: Plugin<TData, TParams>[],
) {
return useRequestImplement<TData, TParams>(service, options, [
...(plugins || []),
useDebouncePlugin,
useLoadingDelayPlugin,
usePollingPlugin,
useRefreshOnWindowFocusPlugin,
useThrottlePlugin,
useAutoRunPlugin,
useCachePlugin,
useRetryPlugin,
] as Plugin<TData, TParams>[]);
}
export default useRequest;
整体解读
抛开import、type, 这三十行代码实际上只有一句话:
function useRequest(service, options, plugins) {
return useRequestImplement(service, options, [
...(plugins || []),
// 默认插件们
];
}
export default useRequest;
可见useRequest方法实际就只是返回了它隔壁useRequestImplement, 同时多带了一些默认插件. 插件具体功能暂且按下不表, 还是先看看更重要的useRequestImplement.ts.
出入参与实例化 · useRequestImplement.ts
先上源码.
源码
import useCreation from '../../useCreation';
import useLatest from '../../useLatest';
import useMemoizedFn from '../../useMemoizedFn';
import useMount from '../../useMount';
import useUnmount from '../../useUnmount';
import useUpdate from '../../useUpdate';
import Fetch from './Fetch';
import type { Options, Plugin, Result, Service } from './types';
function useRequestImplement<TData, TParams extends any[]>(
service: Service<TData, TParams>,
options: Options<TData, TParams> = {},
plugins: Plugin<TData, TParams>[] = [],
) {
const { manual = false, ...rest } = options;
const fetchOptions = {
manual,
...rest,
};
const serviceRef = useLatest(service);
const update = useUpdate();
const fetchInstance = useCreation(() => {
const initState = plugins.map((p) => p?.onInit?.(fetchOptions)).filter(Boolean);
return new Fetch<TData, TParams>(
serviceRef,
fetchOptions,
update,
Object.assign({}, ...initState),
);
}, []);
fetchInstance.options = fetchOptions;
// run all plugins hooks
fetchInstance.pluginImpls = plugins.map((p) => p(fetchInstance, fetchOptions));
useMount(() => {
if (!manual) {
// useCachePlugin can set fetchInstance.state.params from cache when init
const params = fetchInstance.state.params || options.defaultParams || [];
// @ts-ignore
fetchInstance.run(...params);
}

