r3nanp / trpc-swr

tRPC-ified SWR hooks

Home Page:https://trpc-swr.vercel.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

trpc-swr

trpc-swr

tRPC-ified SWR hooks

Installation

npm install trpc-swr @trpc/client @trpc/server

Usage

First, create your fully typed hooks using your router type:

// trpc.ts
import { createSWRProxyHooks } from "trpc-swr";
// `import type` ensures this import is fully erased at runtime
import type { AppRouter } from "./server/router";

// Pass the tRPC configuration object in here
// note that you should pass data transformers (https://trpc.io/docs/data-transformers) here
export const trpc = createSWRProxyHooks<AppRouter>({
  links: [
    httpBatchLink({
      url: "http://localhost:3000/api/trpc",
    }),
  ],
});

Then, add the trpc.Provider to your root App component:

// _app.tsx
import { createTRPCClient } from "@trpc/client";
import { trpc } from "../utils/trpc";

const App = ({ pageProps }) => {
  // create a tRPC vanilla client
  const [client] = useState(() => trpc.createClient());

  return (
    <trpc.Provider client={client}>
      <Component {...pageProps} />
    </trpc.Provider>
  );
};

Tip: For SWR's global configuration, wrap this provider with SWRConfig.

useSWR

Now use trpc to query in a component:

// profile.tsx
import { trpc } from "./trpc";

const Profile = (props: { userId: string }) => {
  const { data, isLoading } = trpc.user.get.useSWR({ id: props.userId });

  return (
    <div>
      Name:{" "}
      {!data && isLoading
        ? "loading..."
        : data
        ? data.name
        : "User does not exist"}
    </div>
  );
};

trpc.useSWR functions the same and accepts all the options that SWR's useSWR hook does. It is only a very small wrapper that adds tRPC types and creates a fetcher using tRPC's vanilla client.

Mutations

You can use trpc.useSWRMutation api to get a tRPC client for mutations:

// profile.tsx
import { trpc } from "./trpc";

const Profile = (props: { userId: string }) => {
  // get `mutate` from trpc.useSWR
  // this is a bound mutate (https://swr.vercel.app/docs/mutation#bound-mutate)
  const { data, mutate, isLoading } = trpc.user.get.useSWR({
    id: props.userId,
  });

  const { trigger } = trpc.user.changeName.useSWRMutation();

  return (
    <div>
      <div>
        Name:{" "}
        {!data && isLoading
          ? "loading..."
          : data
          ? data.name
          : "User does not exist"}
      </div>

      <button
        onClick={() => {
          // you would typically get this from user input
          // but it is hardcoded here to simplify the example
          const newName = "Jack";

          // `mutate` revalidates the `user.get` key above
          // so it is refetched after the mutation is complete
          mutate(
            () => {
              return trigger({
                id: props.userId,
                newName,
              });
            }, // use optimisticData to show new name before mutation completes
            { optimisticData: { name: newName } }
          );
        }}
      ></button>
    </div>
  );
};

Preloading data

This is useful for kicking off a request early when you know you'll need the data soon.

// UserList.tsx

const UserList = () => {
  const { data: users } = trpc.user.getAll.useSWR();

  const handleHover = (id: number) => {
    // Preload the data once the user hovers
    // This makes sure we have the user object in SWR cache when the user clicks the link
    trpc.user.get.preload({ id });
  };

  return (
    <ul>
      {users.map((user) => (
        <li onHover={() => handleHover(user.id)} key={user.id}>
          <Link href={`/users/${user.id}`}>
            <a>{user.name}</a>
          </Link>
        </li>
      ))}
    </ul>
  );
};

SSG & SSR

To prefetch data on the server, you must provide a serializable key.

const HomePage: NextPage = ({ fallback }) => {
  return (
    <SWRConfig value={{ fallback }}>
      <h1>Home</h1>
      <Profile userId="1" />
    </SWRConfig>
  );
};

const Profile = (props: { userId: string }) => {
  // The data is already available in the UI
  const { data, isLoading } = trpc.user.get.useSWR({
    id: props.userId,
  });

  return (
    <div>
      Name:{" "}
      {!data && isLoading
        ? "loading..."
        : data
        ? data.name
        : "User does not exist"}
    </div>
  );
};

export const getServerSideProps = () => {
  const client = trpc.createClient();
  // Manually fetch the data using the native trpc client
  const { data } = await client.query("user.get", { id: "1" });

  return {
    props: {
      fallback: {
        // Get a serialized key to the data
        [trpc.user.get.getKey({ id: "1" })]: data,
      },
    },
  };
};

About

tRPC-ified SWR hooks

https://trpc-swr.vercel.app

License:MIT License


Languages

Language:TypeScript 94.9%Language:JavaScript 2.9%Language:CSS 2.0%Language:Shell 0.2%