Query And Mutation Template
Section titled “Query And Mutation Template”Use this when adding server state to a feature.
The owning feature owns:
- query keys
- query option factories
- mutation hooks
- invalidation behavior
Query keys
Section titled “Query keys”import type { {Feature}Search } from "./types";
export const {feature}QueryKeys = { all: ["{feature}"] as const, list: (search: {Feature}Search) => ["{feature}", search] as const, detail: (id: string) => ["{feature}-detail", id] as const,} as const;Rules:
- keep keys serializable
- use typed object params for list keys
- keep detail keys separate from list keys
Query options
Section titled “Query options”import { queryOptions } from "@tanstack/react-query";import { getResponseStatus, isRetryableStatus } from "@legaciti/platform-query";import { list{Feature}Items, get{Feature}Detail } from "./api";import { {feature}QueryKeys } from "./query-keys";
export const {feature}ListQueryOptions = (search: {Feature}Search) => queryOptions({ queryKey: {feature}QueryKeys.list(search), queryFn: async () => list{Feature}Items(search), placeholderData: (previous) => previous, retry: (failureCount, error: unknown) => { const status = getResponseStatus(error); return failureCount < 2 && isRetryableStatus(status); }, });
export const {feature}DetailQueryOptions = (id: string) => queryOptions({ queryKey: {feature}QueryKeys.detail(id), queryFn: async () => get{Feature}Detail(id), staleTime: 0, retry: false, });Mutation hook
Section titled “Mutation hook”import { useMutation, useQueryClient } from "@tanstack/react-query";import { emitCacheInvalidations } from "@legaciti/platform-events";import { update{Feature}Item } from "./api";import { {feature}QueryKeys } from "./query-keys";
export function useUpdate{Feature}Mutation() { const queryClient = useQueryClient();
return useMutation({ mutationFn: update{Feature}Item, onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: {feature}QueryKeys.all }); queryClient.invalidateQueries({ queryKey: {feature}QueryKeys.detail(variables.id), });
emitCacheInvalidations([ { queryKey: {feature}QueryKeys.all }, { queryKey: {feature}QueryKeys.detail(variables.id) }, ]); }, });}- raw write transport functions stay in
api.ts mutations.tsowns cache update behavior- do not define ad hoc query keys inline inside components
- do not statically import server function modules into client-safe files