After much requests we are excited to announce the release of the new WunderGraph React Query client. This new client is built on top of TanStack React Query, a powerful data fetching library for React. It allows you to consume WunderGraph queries, mutations and subscriptions fully typesafe with React Query.
We took all the lessons learned from building our new SWR integration and applied them to this new client. This means that you can use the same features as with the SWR integration, like optimistic updates, invalidating queries, and more with a similar easy to use and typesafe API.
Currently we only support React, but thanks to TanStack we are now able to add support for other frameworks like Vue, Solid.js and soon Svelte. We would love to have your help in building these integrations. Check out the React Query source code to get started. ❤️
What's new
Let's dive a bit into what's new and how some of the React Query features work with WunderGraph.
Queries
const { data, error } = useQuery({
operationName: 'Weather',
input: {
forCity: 'Berlin',
},
})
Conditionally fetching data:
const { data: user } = useUser()
const { data, error, refetch } = useQuery({
operationName: 'ProtectedWeather',
input: {
forCity: 'Berlin',
},
enabled: !!user,
})
Note that refetch
is slightly different from SWR, instead mutate
we can call refetch
to refetch a specific query.
Turn queries into live queries, live queries are refetched on a interval on the WunderGraph server.
const { data, error } = useQuery({
operationName: 'Weather',
input: {
forCity: 'Berlin',
},
liveQuery: true,
})
Subscriptions
Build realtime apps with subscriptions.
const { data, error, isLoading, isSubscribed } = useSubscription({
operationName: 'Countdown',
input: {
from: 100,
},
})
Mutations
const { data, error, mutate, mutateAsync } = useMutation({
operationName: 'SetName',
})
mutate({ name: 'Eelco' })
// Async mutate
const result = await mutateAsync({ name: 'Eelco' })
Invalidating queries
Let's say we have a query that fetches the current user's profile in one component and we have a form that updates the profile. We can add an onSuccess
handler to the mutation that calls queryClient.invalidateQueries
on the GetProfile
query and trigger a refetch and update the internal React Query cache.
const Profile = () => {
const { data, error } = useQuery({
operationName: 'GetProfile',
})
return <div>{data?.getProfile.name}</div>
}
const FormComponent = () => {
const queryClient = useQueryClient();
const { data, error, mutate } = useMutation({
operationName: 'UpdateProfile',
onSuccess() {
// invalidate the query
queryClient.invalidateQueries(queryKey({ operationName: 'GetProfile' }));
},
})
const onSubmit = (event) => {
e.preventDefault();
const data = new FormData(event.target);
mutate(data)
}
return <form onSubmit={onSubmit}><input name="name" /><button type="submit">Save></button></form>
}
Now we could even make this fully optimistic by updating the GetProfile
cache instead and then refetching it, it would look something like this:
const FormComponent = () => {
const queryClient = useQueryClient();
const { data, error, mutate } = useMutation({
operationName: 'UpdateProfile',
onMutate: async (data) => {
const key = queryKey({ operationName: 'GetProfile' })
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await queryClient.cancelQueries(key)
// Snapshot the previous value
const previousProfile = queryClient.getQueryData<Profile>(key)
// Optimistically update to the new value
if (previousProfile) {
queryClient.setQueryData<Profile>(key, {
...previousProfile,
...data
})
}
return { previousProfile }
},
// If the mutation fails,
// use the context returned from onMutate to roll back
onError: (err, variables, context) => {
if (context?.previousProfile) {
queryClient.setQueryData<Profile>(queryKey({ operationName: 'GetProfile' }), context.previousProfile)
}
},
// Always refetch after error or success:
onSettled: () => {
queryClient.invalidateQueries(queryKey({ operationName: 'GetProfile' }))
},
})
const onSubmit = (event) => {
e.preventDefault();
const data = new FormData(event.target);
mutate(data)
}
return <form onSubmit={onSubmit}><input name="name" /><button type="submit">Save></button></form>
}
Check out the reference and example app below to learn more about the new React Query integration.
Resources
Summary
You can now easily integrate WunderGraph with React Query and start building end-to-end typesafe applications with WunderGraph. Thanks go out to Tanstack for making this great data fetching library.
We would love to know more about your experience with React Query and looking forward to seeying what you build with it. Share it in the comments below or come join us on our Discord server.