trpc-swr v0.1.5
trpc-swr
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,
},
},
}
}
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago