SWR 请求封装实践

//src/lib/swrFetcher.js
/**
 * SWR 请求封装
 * 1. 基于 SWR 和 axios 封装的 GET 请求 hook
 * 2. 用于执行非 GET 请求(例如登录、提交表单等)的自定义 hook
 * 3. 生成唯一的 key,确保相同参数的序列化结果一致
 * 4. 使用 json-stable-stringify 来实现稳定的序列化
 * 5. 使用 useSWR 和 useSWRMutation 来实现请求和响应的缓存、重验证等特性
 * 6. 使用 httpAxios 实例来发起请求
 */
"use client";
import useSWR from "swr";
import useSWRMutation from "swr/mutation";
import stableStringify from "json-stable-stringify";
import httpAxios from "@/lib/httpAxios";

/**
 * 根据 URL、HTTP 方法和查询参数生成唯一的 key
 * 使用json-stable-stringify 来实现稳定的序列化:确保相同参数的序列化结果一致
 * @param {string} url
 * @param {string} method
 * @param {object} params
 * @returns {string}
 */
function generateRequestKey(url, method, params) {
  const paramsString = params ? stableStringify(params) : "";
  return `${method.toUpperCase()}::${url}::${paramsString}`;
}

/**
 * useSwrRequest - 基于 SWR 和 axios 封装的 GET 请求 hook
 * 主要用于 GET 请求和数据查询,支持缓存、重验证等特性
 *
 * @param {object} options - Axios 请求配置,包括 url、method、params、data 等,
 *                           另外支持 isEnabled(默认 true)控制是否自动发起请求
 * @param {object} swrConfig - SWR 的配置项
 * @returns {object} SWR 响应对象,额外附加 responseData(即后端 data 字段)和 requestKey
 */
export function useRequest(options, swrConfig = {}) {
  const { isEnabled = true, url, method = "GET", params } = options;
  const requestKey =
    isEnabled && url ? generateRequestKey(url, method, params) : null;

  const fetcher = async () => {
    const response = await httpAxios.request(options);
    return { data: response.data, headers: response.headers };
  };

  const swrResponse = useSWR(requestKey, fetcher, swrConfig);

  return {
    ...swrResponse,
    responseData: swrResponse.data ? swrResponse.data.data : undefined,
    headers: swrResponse.data ? swrResponse.data.headers : undefined,
    requestKey: requestKey || "",
  };
}

/**
 * swrMutation - 用于执行非 GET 请求(例如登录、提交表单等)的自定义 hook
 * 针对 POST/PUT/DELETE 等非幂等操作,使用 SWR 提供的 mutation 机制,通过手动调用 trigger 发起请求,避免自动缓存和重复请求的问题
 *
 * @param {string} key - 唯一标识,通常为 URL
 * @param {object} defaultOptions - 默认的 axios 请求配置(例如 URL、method 等)
 * @param {object} swrMutationConfig - SWR Mutation 的配置项
 * @returns {object} 包含 trigger、data、error、isMutating 等字段
 */
export function useMutation(key, defaultOptions = {}, swrMutationConfig = {}) {
  const mutationFetcher = async (_, { arg }) => {
    // 动态传入的参数与默认配置合并
    const requestOptions = { ...defaultOptions, ...arg };
    const response = await httpAxios.request(requestOptions);
    return { data: response.data, headers: response.headers };
  };

  return useSWRMutation(key, mutationFetcher, swrMutationConfig);
}

SWR 是一个 React Hooks 库,用于数据获取、缓存和重验证等场景,可以方便地实现数据请求的缓存、重验证等特性。在实际开发中,可以使用 SWR 来简化数据请求的处理,提高开发效率。我们可以通过封装 useRequest 和 useMutation 等自定义 hook 来实现不同类型的请求,从而更好地利用 SWR 的特性。而无论是 GET 请求还是非 GET 请求,都可以通过 SWR 来实现数据请求的缓存、重验证等特性,提高页面性能和用户体验。