fenghuo/packages/client/src/api/hooks/useEntity.ts

116 lines
4.3 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useTRPC, type RouterInputs, type RouterOutputs } from "../trpc";
import { useQueryClient } from "@tanstack/react-query";
import { useMutation, type UseMutationResult } from "@tanstack/react-query";
/**
* 定义 MutationType 类型,用于提取指定实体类型的特定 mutation 方法名。
* @template T - 实体类型的键名(如 'post', 'user'
* @description 该类型通过遍历 RouterInputs[T] 的键名,筛选出符合条件的 mutation 方法名(如 'create', 'update' 等)。
*/
type MutationType<T extends keyof RouterInputs> = keyof {
[K in keyof RouterInputs[T]]: K extends
| "create"
| "update"
| "deleteMany"
| "softDeleteByIds"
| "restoreByIds"
| "updateOrder"
? RouterInputs[T][K]
: never;
};
/**
* 定义 MutationOptions 类型,用于配置特定 mutation 方法的回调函数。
* @template T - 实体类型的键名
* @template K - mutation 方法名
* @description 该类型包含一个可选的 onSuccess 回调函数,用于在 mutation 成功时执行。
*/
type MutationOptions<
T extends keyof RouterInputs,
K extends MutationType<T>,
> = {
onSuccess?: (
data: RouterOutputs[T][K], // mutation 成功后的返回数据
variables: RouterInputs[T][K], // mutation 的输入参数
context?: unknown // 可选的上下文信息
) => void;
};
/**
* 定义 EntityOptions 类型,用于配置实体类型的所有 mutation 方法的回调函数。
* @template T - 实体类型的键名
* @description 该类型是一个对象,键为 mutation 方法名,值为对应的 MutationOptions 配置。
*/
type EntityOptions<T extends keyof RouterInputs> = {
[K in MutationType<T>]?: MutationOptions<T, K>;
};
/**
* 工具类型:更新为 TanStack Query 的 UseMutationResult 类型。
* @template T - 实体类型的键名
* @template K - mutation 方法名
* @description 该类型用于定义 mutation 函数的返回类型,适配新版 tRPC。
*/
export type MutationResult<
T extends keyof RouterInputs,
K extends MutationType<T>,
> = UseMutationResult<
RouterOutputs[T][K], // mutation 成功后的返回数据
Error, // mutation 的错误类型
RouterInputs[T][K], // mutation 的输入参数
unknown // mutation 的上下文类型
>;
/**
* 自定义 Hook用于处理实体的 mutation 操作,并内置缓存失效机制。
* @template T - 实体类型的键名(如 'post', 'user'
* @param {T} key - 实体键名
* @param {EntityOptions<T>} [options] - 可选的 mutation 回调函数配置
* @returns 返回一个包含多个 mutation 函数的对象
* @description 该 Hook 封装了常见的 mutation 操作(如 create, update, deleteMany 等),并在每次 mutation 成功后自动失效相关缓存。
*/
export function useEntity<T extends keyof RouterInputs>(
key: T,
options?: EntityOptions<T>
) {
const trpc = useTRPC();
const queryClient = useQueryClient();
/**
* 创建 mutation 处理函数。
* @template K - mutation 方法名
* @param {K} mutation - mutation 方法名
* @returns 返回一个配置好的 mutation 函数
* @description 该函数根据传入的 mutation 方法名,生成对应的 mutation 函数,并配置 onSuccess 回调。
*/
const createMutationHandler = <K extends MutationType<T>>(mutation: K) => {
// 获取对应的 tRPC mutation 配置
const mutationOptions = trpc[key as keyof typeof trpc][mutation as any].mutationOptions();
// 使用 TanStack Query 的 useMutation 创建 mutation
return useMutation({
...mutationOptions,
onSuccess: (data, variables, context) => {
// 调用原始配置的 onSuccess 回调(如果有)
mutationOptions.onSuccess?.(data as any, variables as any, context);
// 失效指定实体的缓存
queryClient.invalidateQueries({ queryKey: [key] });
// 调用用户自定义的 onSuccess 回调
options?.[mutation]?.onSuccess?.(data as any, variables as any, context);
},
}) as MutationResult<T, K>;
};
// 返回包含多个 mutation 函数的对象
return {
create: createMutationHandler("create"),
createCourse: createMutationHandler("createCourse"),
update: createMutationHandler("update"),
deleteMany: createMutationHandler("deleteMany"),
softDeleteByIds: createMutationHandler("softDeleteByIds"),
restoreByIds: createMutationHandler("restoreByIds"),
updateOrder: createMutationHandler("updateOrder"),
updateOrderByIds: createMutationHandler("updateOrderByIds"),
};
}