ssr is labled under the
ssr
tag because it is using @adeora/solid-query instead of @tanstack/solid-query - It is planned to be released under the tanstack org on version 5. Check out the ssr branch
I recommend using Create JD App but if you want to create a project from scratch, you can follow the steps below:
npm install @trpc/client @trpc/server solid-trpc@next @tanstack/solid-query
// utils/trpc.ts
import { IAppRouter } from "@/whereMyRouterAt"; // your router type
import { createTRPCSolid } from "solid-trpc";
import { httpBatchLink } from "@trpc/client";
import { QueryClient } from "@tanstack/solid-query";
export const trpc = createTRPCSolid<IAppRouter>();
export const client = trpc.createClient({
links: [
httpBatchLink({
url: "/api/trpc",
}),
],
});
export const queryClient = new QueryClient();
// entry-client.tsx
import { mount, StartClient } from "solid-start/entry-client";
import { client, queryClient, trpc } from "./utils/trpc";
mount(
() => (
<trpc.Provider client={client} queryClient={queryClient}>
<StartClient />
</trpc.Provider>
),
document
);
// routes/example.tsx
import { trpc } from "./utils/trpc";
import { createSignal } from "solid-js";
const [name, setName] = createSignal("");
const res = trpc.queryName.useQuery(() => ({ name: name() })); // this will be called onMount and when name changes
export default function Example() {
return (
{...}
)
}
Solid tRPC input is considered to be a Solid accessor, meaning that you are required to pass a callback and SQ will rerun the tRPC endpoint whenever the signal changes.
const [name, setName] = createSignal("John");
trpc.example.hello.useQuery(name); // ✅
trpc.example.hello.useQuery(name()); // ❌
trpc.example.useQuery(()=> name().slice(1)); // ✅
// or even
trpc.example.useQuery(()=> "John"); // ✅ will be called once
To use the output of the query, you must remember to not destructure elements. Doing so violates the reactivity of the query result. This principle is general to Solid, please read more here solidjs/solid#408 (comment).
const { data, refetch } = trpc.example.hello.useQuery(name()); // ❌ data will be evaluated only once and not update
const NavBar = () => {
return <div>{data}</div>;
}
// valid
const queryRes = trpc.example.hello.useQuery(name()); // ✅
const NavBar = () => {
return <div>{queryRes.data}</div>;
}
If you are using the enabled
property make sure you follow Solid Query rules:
const [enabled, setEnabled] = createSignal(false);
const query = trpc.queryName.useQuery(() => "hey there", {
// ❌ passing a signal directly is not reactive
// enabled: enabled(),
// ✅ passing a function that returns a signal is reactive
get enabled() {
return enabled();
},
});
To invalidate queries, please see the following example of using utils
which come as part of the trpc
object you created through createTRPCSolid.
// NavBar.tsx
const queryRes = trpc.example.hello.useQuery(name()); // ✅ this will refetch on invalidation in Footer.tsx
const NavBar = () => {
return <div>{queryRes.data}</div>;
}
// Footer.tsx
const Footer = () => {
const trpcUtils = trpc.useContext()
const sayHelloAgain = () => {
trpcUtils.example.hello.invalidate()
}
return <button onClick={sayHelloAgain}>say hello again</div>;
}