[ahooks] useRequest源码阅读(二)

上一节我们分析了useRequest核心的Fetch模块的原理,这一节我们来看它是怎么使用的

useRequest

我们先来看useRequest这个hooks,可以看到它调用了useRequestImplement,并传入三个参数: service, optionsplugins,这里可以看到内部的plugins优先级要高于外部传入的:

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;

useRequestImplement

先是对传入的参数进行默认值的赋值,生成fetchOptions,然后调用new Fetch()方法生成fetchInstance实例,这里可以看到紧接着就是运行所有插件获取插件的返回值,然后赋值给Fetch实例的pluginImpls属性:

ts 复制代码
const fetchInstance = useCreation(() => { 
    const initState = plugins.map((p) => p?.onInit?.(fetchOptions)).filter(Boolean); 
    // Generation Fetch Instance
    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));

接下来是判断初始化时是否自动执行一次,如果条件满足,则在组件挂载时执行初始化参数并调用实例的run 方法

在组件卸载时执行cancel方法

最后是组件返回包括data在内的各个state和方法

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 isDev from '../../utils/isDev';

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, ready = true, ...rest } = options;

  if (isDev) {
    if (options.defaultParams && !Array.isArray(options.defaultParams)) {
      console.warn(`expected defaultParams is array, got ${typeof options.defaultParams}`);
    }
  }

  const fetchOptions = {
    manual,
    ready,
    ...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 && ready) {
      // useCachePlugin can set fetchInstance.state.params from cache when init
      const params = fetchInstance.state.params || options.defaultParams || [];
      // @ts-ignore
      fetchInstance.run(...params);
    }
  });

  useUnmount(() => {
    fetchInstance.cancel();
  });

  return {
    loading: fetchInstance.state.loading,
    data: fetchInstance.state.data,
    error: fetchInstance.state.error,
    params: fetchInstance.state.params || [],
    cancel: useMemoizedFn(fetchInstance.cancel.bind(fetchInstance)),
    refresh: useMemoizedFn(fetchInstance.refresh.bind(fetchInstance)),
    refreshAsync: useMemoizedFn(fetchInstance.refreshAsync.bind(fetchInstance)),
    run: useMemoizedFn(fetchInstance.run.bind(fetchInstance)),
    runAsync: useMemoizedFn(fetchInstance.runAsync.bind(fetchInstance)),
    mutate: useMemoizedFn(fetchInstance.mutate.bind(fetchInstance)),
  } as Result<TData, TParams>;
}

export default useRequestImplement;

总结

至此useRequest的核心执行流程便分析完了,随后会不定时补出各个插件的源码分析,感谢各位的阅读

相关推荐
dly_blog37 分钟前
setup 函数完整指南!
前端·javascript·vue.js
霍理迪1 小时前
基础CSS语法
前端·css
粟悟饭&龟波功1 小时前
【GitHub热门项目精选】(2025-12-19)
前端·人工智能·后端·github
流浪法师121 小时前
MyPhishing-Web:AI 驱动的钓鱼邮件检测可视化平台
前端·人工智能
写代码的jiang1 小时前
【无标题】实战:Vue3 + Element Plus 实现树形选择器全量预加载与层级控制
前端·javascript·vue.js
晚烛1 小时前
实战前瞻:构建高可靠、低延迟的 Flutter + OpenHarmony 智慧交通出行平台
前端·javascript·flutter
WHOVENLY2 小时前
【javaScript】- 作用域[[scope]]
前端·javascript
来杯三花豆奶2 小时前
Vue3 Pinia 从入门到精通
前端·javascript·vue.js
syt_10132 小时前
设计模式之-工厂模式
javascript·单例模式·设计模式
卡布叻_星星2 小时前
Docker之Nginx前端部署(Windows版-x86_64(AMD64)-离线)
前端·windows·nginx