GithubHelp home page GithubHelp logo

briancoit / trpc-swr Goto Github PK

View Code? Open in Web Editor NEW

This project forked from sannajammeh/trpc-swr

0.0 0.0 0.0 72 KB

tRPC-ified SWR hooks

License: MIT License

Shell 0.34% JavaScript 6.32% TypeScript 93.34%

trpc-swr's Introduction

trpc-swr

tRPC-ified SWR hooks

Installation

npm install trpc-swr @trpc/client

Usage

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

// trpc.ts
import { createSWRHooks } from 'trpc-swr'
// `import type` ensures this import is fully erased at runtime
import type { AppRouter } from './router'

export const trpc = createSWRHooks<AppRouter>()

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

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

const App = () => {
  // create a tRPC vanilla client
  // see https://trpc.io/docs/vanilla
  // note that you should pass data transformers (https://trpc.io/docs/data-transformers) here
  const [client] = useState(() =>
    createTRPCClient({ url: 'http://localhost:3000/api/trpc' })
  )

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

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, isValidating } = trpc.useSWR(['user.get', { id: props.userId }])

  return (
    <div>
      Name: {!data && isValidating
        ? '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.useContext 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, isValidating } = trpc.useSWR(['user.get', {
    id: props.userId,
  }])
  const { client } = trpc.useContext()

  return (
    <div>
      <div>
        Name: {!data && isValidating
          ? '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 client.mutation('user.changeName', {
                id: props.userId,
                newName,
              })
            }, // use optimisticData to show new name before mutation completes
            { optimisticData: { name: newName } },
          )
        }}
      >
      </button>
    </div>
  )
}

You can also use trpc.useContext to get a mutate function which is the same as SWR's global mutate. However, you will have the pass the same key, meaning the query path and input that you passed to useSWR. Here it is with the same example as above:

// profile.tsx
import { trpc } from './trpc'

const Profile = (props: { userId: string }) => {
  const { data, isValidating } = trpc.useSWR(['user.get', {
    id: props.userId,
  }])

  // get `mutate` from `trpc.useContext`
  const { client, mutate } = trpc.useContext()

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

      <button
        onClick={() => {
          const newName = 'Jack'

          mutate(
            // must pass in exact same query path and input
            // to revalidate the query key
            // note that you can use `matchMutate` to
            // revalidate query keys with the same path
            ['user.get', { id: props.userId }],
            () => {
              return client.mutation('user.changeName', {
                id: props.userId,
                newName,
              })
            },
            { optimisticData: { name: newName } },
          )
        }}
      >
      </button>
    </div>
  )
}

useSWRInfinite

trpc-swr also provides a useSWRInfinite wrapper. Create your typed useSWRInfinite:

// trpc.ts
import { createSWRHooks } from 'trpc-swr'
import { getUseSWRInfinite } from 'trpc-swr/infinite'

// `import type` ensures this import is fully erased at runtime
import type { AppRouter } from './router'

export const trpc = createSWRHooks<AppRouter>()
export const useSWRInfinite = getUseSWRInfinite<AppRouter>()

This requires using getUseSWRInfinite and passing in the AppRouter type again, so we can take full advantage of tree shaking and remove the functions that your app does not use.

Now use it in a component:

// users.tsx
import { useSWRInfinite } from './trpc'

const Users = () => {
  const { data, size, setSize } = useSWRInfinite(
    // pass in path
    'user.get',
    (index, previousPageData) => {
      if (index !== 0 && !previousPageData) return null

      // return a value for the input of the path you passed
      // `user.get` in this case
      return [{ id: index }]
    },
  )

  if (!data) {
    return <div>Loading...</div>
  }

  return (
    <>
      <div>
        {data.map((user) => {
          return <p key={user.name}>{user.name}</p>
        })}
      </div>

      <button onClick={() => setSize(size + 1)}>Load More Users</button>
    </>
  )
}

Utility

matchMutate

The matchMutate utility allows you to invalidate query keys that match a tRPC route. Create your typed useMutateMutate function:

// trpc.ts
import { createSWRHooks, getUseMatchMutate } from 'trpc-swr'
// `import type` ensures this import is fully erased at runtime
import type { AppRouter } from './router'

export const trpc = createSWRHooks<AppRouter>()
export const useMatchMutate = getUseMatchMutate<AppRouter>()

Now use it in a component:

import { trpc, useMatchMutate } from './trpc'

// profiles.tsx
const Profiles = () => {
  const userBobData = trpc.useSWR([
    'user.get',
    {
      name: 'Bob',
    },
  ])

  const userAvaData = trpc.useSWR([
    'user.get',
    {
      name: 'Ava',
    },
  ])

  const matchMutate = useMatchMutate()

  return (
    <div>
      {[userBobData, userAvaData].map(({ data: user, isValidating }) => (
        <div>
          Name: {!data && isValidating
            ? 'loading...'
            : data
            ? data.name
            : 'User does not exist'}
        </div>
      ))}
      <button onClick={() => matchMutate('user.get')}>
        Revalidate all tRPC `user.get` queries
      </button>
    </div>
  )
}

trpc-swr's People

Contributors

sachinraja avatar renovate-bot avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.