Skip to content
tRPC

React without TanStack Query

Render-as-you-fetch with use() and Suspense in @trpc12/experimental-react, where cache features are links.

On this page

Two experimental packages read tRPC in React with use() and Suspense, without TanStack Query. Both are experimental as a whole: the package name says so, every export is @stability experimental, and the API may change in any release. For a stable React integration, use TanStack Query.

PackageModel
@trpc12/experimental-reactPromises: loaders start queries, components read them with use(). Features are links, opt-in.
@trpc12/experimental-react-atomEffect Atoms: query and mutation atoms read with useAtomSuspense (React atoms).

This page is @trpc12/experimental-react: render-as-you-fetch, after raf-query. A route loader (or an event handler) calls .query(), which starts the request and returns a promise. The component reads that promise with useQuery() and use(). Components don't start requests.

import {
  function createReactClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: ReactClientOptions<TSource, TLinks>): ReactClient<TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>>createReactClient,
  function standardLinks(opts?: StandardLinksOptions): StandardLinksstandardLinks,
  function useQuery<T, E>(promise: QueryPromise<T, E>): QueryPromise<T, E>useQuery,
  type type QueryPromise<T, E = unknown> = TrpcPromise<T, E> & Thenable<T>QueryPromise,
} from '@trpc12/experimental-react';
import { function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink, function routerType<TRouter>(): RouterType<TRouter>routerType } from '@trpc12/trpc/client';
import { const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense, function use<T>(usable: React.Usable<T>): Tuse } from 'react';
import type { 
type AppRouter = {
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}
AppRouter
} from './server';
export const
const trpc: ReactClient<TrpcClient<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
=
createReactClient<RouterType<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}>, readonly [cache: ...]>(opts: ReactClientOptions<...>): ReactClient<...>
createReactClient
({
TypedClientOptions<RouterType<{ post: { byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { output: Post; errors: TrpcError<...>; services: never; unmapped: never; }>; list: BuildProcedure<...>; create: BuildProcedure<...>; }; }>, readonly [cache: ...]>.router: RouterType<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}>
router
:
routerType<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}>(): RouterType<...>
routerType
<
type AppRouter = {
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}
AppRouter
>(),
TypedClientOptions<RouterType<{ post: { byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{ id: ZodString; }, $strip>>, "query", { output: Post; errors: TrpcError<...>; services: never; unmapped: never; }>; list: BuildProcedure<...>; create: BuildProcedure<...>; }; }>, readonly [cache: ...]>.links: readonly [cache: TrpcLink<{}, any>, structuralSharing: TrpcLink<{}, any>, refetchOnMount: TrpcLink<{}, any>, refetchOnWindowFocus: TrpcLink<{}, any>, refetchOnReconnect: TrpcLink<{}, any>, invalidateOnMutation: TrpcLink<{}, any>, retry: TrpcLink<{}, any>, TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>]
links
: [...function standardLinks(opts?: StandardLinksOptions): StandardLinksstandardLinks({ CacheLinkOptions.staleTime?: number | undefinedstaleTime: 10_000 }),
httpLink<{
    url: string;
}>(opts: {
    url: string;
}): TrpcLink<{
    form: JsonForm;
    provides: "response";
}, any>
httpLink
({ url: stringurl: '/trpc' })],
}); // The route's loader starts the request; the navigation doesn't wait for it. export const
const loader: (args: {
    params: {
        id: string;
    };
}) => {
    post: QueryPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    }, ClientError<TrpcError<"NOT_FOUND", {
        id: string;
    }> | InputValidationError<{
        readonly code: "invalid_type";
        readonly expected: $ZodInvalidTypeExpected;
        readonly path: readonly [] | readonly ["id"];
        readonly message: string;
    } | {
        readonly code: "too_big";
        readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
        readonly maximum: string | number;
        readonly inclusive?: boolean | undefined;
        readonly exact?: boolean | undefined;
        readonly path: readonly [] | readonly [...];
        readonly message: string;
    } | ... 9 more ... | {
        ...;
    }>, JsonForm>>;
}
loader
= (
args: {
    params: {
        id: string;
    };
}
args
: {
params: {
    id: string;
}
params
: { id: stringid: string } }) => ({
post: QueryPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<TrpcError<"NOT_FOUND", {
    id: string;
}> | InputValidationError<{
    readonly code: "invalid_type";
    readonly expected: $ZodInvalidTypeExpected;
    readonly path: readonly [] | readonly ["id"];
    readonly message: string;
} | {
    readonly code: "too_big";
    readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
    readonly maximum: string | number;
    readonly inclusive?: boolean | undefined;
    readonly exact?: boolean | undefined;
    readonly path: readonly [] | readonly [...];
    readonly message: string;
} | ... 9 more ... | {
    ...;
}>, JsonForm>>
post
:
const trpc: ReactClient<TrpcClient<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
        id: ZodString;
    }, $strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>;
    list: BuildProcedure<RootDef<Context, {}>, "query", {
        output: Post[];
        errors: never;
        services: never;
        unmapped: never;
    }>;
    create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
        ctx: Context;
        ctxAdded: {
            ...;
        };
        inputOut: Unset;
        errors: TrpcError<...>;
        shorts: never;
    }>, ZodObject<...>>, "mutation", {
        ...;
    }>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | InputValidationError<...>, JsonForm>>.query(input: {
    id: string;
}, opts?: CallOptions<{}> | undefined): QueryPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<TrpcError<"NOT_FOUND", {
    id: string;
}> | InputValidationError<{
    readonly code: "invalid_type";
    readonly expected: $ZodInvalidTypeExpected;
    readonly path: readonly [] | readonly ["id"];
    readonly message: string;
} | {
    readonly code: "too_big";
    readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
    readonly maximum: string | number;
    readonly inclusive?: boolean | undefined;
    readonly exact?: boolean | undefined;
    readonly path: readonly [] | readonly [...];
    readonly message: string;
} | ... 9 more ... | {
    ...;
}>, JsonForm>>
query
({ id: stringid:
args: {
    params: {
        id: string;
    };
}
args
.
params: {
    id: string;
}
params
.id: stringid }),
}); function
function Post(props: {
    post: QueryPromise<{
        title: string;
    }>;
}): React.JSX.Element
Post
(
props: {
    post: QueryPromise<{
        title: string;
    }>;
}
props
: {
post: QueryPromise<{
    title: string;
}>
post
: type QueryPromise<T, E = unknown> = TrpcPromise<T, E> & Thenable<T>QueryPromise<{ title: stringtitle: string }> }) {
const
const post: {
    title: string;
}
post
=
use<{
    title: string;
}>(usable: React.Usable<{
    title: string;
}>): {
    title: string;
}
use
(
useQuery<{
    title: string;
}, unknown>(promise: QueryPromise<{
    title: string;
}, unknown>): QueryPromise<{
    title: string;
}, unknown>
useQuery
(
props: {
    post: QueryPromise<{
        title: string;
    }>;
}
props
.
post: QueryPromise<{
    title: string;
}>
post
));
return <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1>{
const post: {
    title: string;
}
post
.title: stringtitle}</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1>;
} <const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense React.SuspenseProps.fallback?: React.ReactNodefallback={<function Spinner(): React.ReactNodeSpinner />}> <
function Post(props: {
    post: QueryPromise<{
        title: string;
    }>;
}): React.JSX.Element
Post
post: QueryPromise<{
    title: string;
}>
post
={
const loaderData: {
    post: QueryPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    }, ClientError<TrpcError<"NOT_FOUND", {
        id: string;
    }> | InputValidationError<{
        readonly code: "invalid_type";
        readonly expected: $ZodInvalidTypeExpected;
        readonly path: readonly [] | readonly ["id"];
        readonly message: string;
    } | {
        readonly code: "too_big";
        readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
        readonly maximum: string | number;
        readonly inclusive?: boolean | undefined;
        readonly exact?: boolean | undefined;
        readonly path: readonly [] | readonly [...];
        readonly message: string;
    } | ... 9 more ... | {
        ...;
    }>, JsonForm>>;
}
loaderData
.
post: QueryPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
}, ClientError<TrpcError<"NOT_FOUND", {
    id: string;
}> | InputValidationError<{
    readonly code: "invalid_type";
    readonly expected: $ZodInvalidTypeExpected;
    readonly path: readonly [] | readonly ["id"];
    readonly message: string;
} | {
    readonly code: "too_big";
    readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
    readonly maximum: string | number;
    readonly inclusive?: boolean | undefined;
    readonly exact?: boolean | undefined;
    readonly path: readonly [] | readonly [...];
    readonly message: string;
} | ... 9 more ... | {
    ...;
}>, JsonForm>>
post
} />
</const Suspense: React.ExoticComponent<React.SuspenseProps>Suspense>;

useQuery finds the cache through the promise, so there is no provider.

Stable promises

Built in, not a link. use() needs the same promise across renders, and these are:

  • One promise per query (path and input, with object keys sorted) while it loads, so calls in flight share one request.
  • The same promise while the data doesn't change. A new one only when it does: a refetch with new data, or setData.
  • Settled promises carry status and value, so use() renders cached data without suspending.

useQuery(promise) returns the query's current promise and re-renders when it changes. useQueryState(promise) gives isFetching, isStale, error, updatedAt and refetch(), for spinners and retry buttons.

Without links, the cache does the least: an entry lives while a request is in flight or a mounted useQuery reads it. Everything else is a link, opt-in one by one:

LinkDoesIn standardLinks()
cacheLink({ staleTime, gcTime })Keeps unread entries gcTime (5 minutes); fresh data (staleTime, 0) makes no requestyes
structuralSharingLink()Refetched data keeps unchanged parts, and unchanged data keeps its promise (no re-render)yes
refetchOnMountLink()A mount on stale data refetches it, except right after the loader's own requestyes
refetchOnWindowFocusLink()Refetches stale, mounted queries when the page is visible againyes
refetchOnReconnectLink()The same when the browser comes back onlineyes
retryLink() (core)Retries failed queries 3 timesyes
invalidateOnMutationLink()After a mutation, invalidates queries and resolves once the mounted ones have refetchedyes

standardLinks() matches TanStack Query's defaults, plus one: like a router after an action, every mutation invalidates queries (all of them, unless invalidates narrows it). Stale data is returned at once and refetched in the background.

Query links are tRPC links: they sit in the same links array, before the link that sends. Write your own with withQueryFeature(link, feature).

Cache methods

await 
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>, "mutation", {
            output: Post | undefined;
            errors: never;
            services: never;
            unmapped: never;
        }>;
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<...>;
        create: BuildProcedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
        title: z.ZodString;
    }, z.core.$strip>>, "mutation", {
        output: Post | undefined;
        errors: never;
        services: never;
        unmapped: never;
    }>;
    byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>;
    list: BuildProcedure<...>;
    create: BuildProcedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    ...;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | InputValidationError<...>, JsonForm>>.invalidate(input?: {
    id: string;
} | undefined): Promise<void>
invalidate
({ id: stringid }); // refetches it if it's on screen
await
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>, "mutation", {
            output: Post | undefined;
            errors: never;
            services: never;
            unmapped: never;
        }>;
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<...>;
        create: BuildProcedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.function invalidate(filter?: QueryFilter): Promise<void>invalidate('post'); // every query under post.*
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>, "mutation", {
            output: Post | undefined;
            errors: never;
            services: never;
            unmapped: never;
        }>;
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<...>;
        create: BuildProcedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
        title: z.ZodString;
    }, z.core.$strip>>, "mutation", {
        output: Post | undefined;
        errors: never;
        services: never;
        unmapped: never;
    }>;
    byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>;
    list: BuildProcedure<...>;
    create: BuildProcedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    ...;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | InputValidationError<...>, JsonForm>>.setData(input: {
    id: string;
}, updater: {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | ((prev: {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined) => {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
})): void
setData
({ id: stringid }, (
prev: {
    ...;
} | undefined
prev
) => ({ ...
prev: {
    ...;
} | undefined
prev
!, title: stringtitle }));
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>, "mutation", {
            output: Post | undefined;
            errors: never;
            services: never;
            unmapped: never;
        }>;
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<...>;
        create: BuildProcedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
        title: z.ZodString;
    }, z.core.$strip>>, "mutation", {
        output: Post | undefined;
        errors: never;
        services: never;
        unmapped: never;
    }>;
    byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>;
    list: BuildProcedure<...>;
    create: BuildProcedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
byId: DecorateQuery<[input: {
    id: string;
}, opts?: CallOptions<{}> | undefined], {
    ...;
}, ClientError<...>>
byId
.
DecorateQuery<[input: { id: string; }, opts?: CallOptions<{}> | undefined], { id: string; title: string; author: string | null; createdAt: string; }, ClientError<TrpcError<"NOT_FOUND", { id: string; }> | InputValidationError<...>, JsonForm>>.getData(input_0: {
    id: string;
}): {
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined
getData
({ id: stringid });
await
const trpc: ReactClient<TrpcClient<{
    post: {
        rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
            title: z.ZodString;
        }, z.core.$strip>>, "mutation", {
            output: Post | undefined;
            errors: never;
            services: never;
            unmapped: never;
        }>;
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
            id: z.ZodString;
        }, z.core.$strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<...>;
        create: BuildProcedure<...>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
.
post: ReactProcedures<ClientRouter<{
    rename: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
        title: z.ZodString;
    }, z.core.$strip>>, "mutation", {
        output: Post | undefined;
        errors: never;
        services: never;
        unmapped: never;
    }>;
    byId: BuildProcedure<InputDef<RootDef<Context, {}>, z.ZodObject<{
        id: z.ZodString;
    }, z.core.$strip>>, "query", {
        output: Post;
        errors: TrpcError<"NOT_FOUND", {
            id: string;
        }>;
        services: never;
        unmapped: never;
    }>;
    list: BuildProcedure<...>;
    create: BuildProcedure<...>;
}, {}, undefined, LinksTypes<...>>>
post
.
rename: {
    mutate(input: {
        id: string;
        title: string;
    }, opts?: CallOptions<{}> | undefined): TrpcPromise<{
        id: string;
        title: string;
        author: string | null;
        createdAt: string;
    } | undefined, CallError<{
        type: "mutation";
        ctx: Context;
        meta: {};
        input: {
            id: string;
            title: string;
        };
        output: Post | undefined;
        errors: InputValidationError<{
            readonly code: "invalid_type";
            readonly expected: z.core.$ZodInvalidTypeExpected;
            readonly path: readonly [] | readonly ["id"] | readonly ["title"];
            readonly message: string;
        } | {
            readonly code: "too_big";
            readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
            ... 4 more ...;
            readonly message: string;
        } | ... 9 more ... | {
            ...;
        }>;
        services: never;
    }, JsonForm, never>>;
}
rename
.
function mutate(input: {
    id: string;
    title: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
    id: string;
    title: string;
    author: string | null;
    createdAt: string;
} | undefined, CallError<{
    type: "mutation";
    ctx: Context;
    meta: {};
    input: {
        id: string;
        title: string;
    };
    output: Post | undefined;
    errors: InputValidationError<{
        readonly code: "invalid_type";
        readonly expected: z.core.$ZodInvalidTypeExpected;
        readonly path: readonly [] | readonly ["id"] | readonly ["title"];
        readonly message: string;
    } | {
        readonly code: "too_big";
        readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
        ... 4 more ...;
        readonly message: string;
    } | ... 9 more ... | {
        ...;
    }>;
    services: never;
}, JsonForm, never>>
mutate
({ id: stringid, title: stringtitle }); // mutations and subscriptions are the plain client's

Server rendering

On the server, create one client per request (isServer defaults to typeof window === 'undefined'; a server's cache never drops entries). After the render, dehydrate(trpc) encodes the settled queries with the links' serializer, so Dates survive with danSON; hydrate(trpc, state) writes them into the browser's client before it renders.

const const state: DehydratedQueriesstate = function dehydrate(trpc: HasStore, opts?: HydrationOptions): DehydratedQueriesdehydrate(
const serverTrpc: ReactClient<TrpcClient<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
serverTrpc
); // send it with the HTML
function hydrate(trpc: HasStore, state: DehydratedQueries, opts?: HydrationOptions): voidhydrate(
const trpc: ReactClient<TrpcClient<{
    post: {
        byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
            id: ZodString;
        }, $strip>>, "query", {
            output: Post;
            errors: TrpcError<"NOT_FOUND", {
                id: string;
            }>;
            services: never;
            unmapped: never;
        }>;
        list: BuildProcedure<RootDef<Context, {}>, "query", {
            output: Post[];
            errors: never;
            services: never;
            unmapped: never;
        }>;
        create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
            ctx: Context;
            ctxAdded: {
                ...;
            };
            inputOut: Unset;
            errors: TrpcError<...>;
            shorts: never;
        }>, ZodObject<...>>, "mutation", {
            ...;
        }>;
    };
}, {}, undefined, LinksTypes<...>>>
trpc
, const state: DehydratedQueriesstate); // in the browser, before hydrateRoot