There are so many articles out about state-management and solving it with Tanstacks React-Query but I was missing the very basic idea. No reducer pattern, just telling how to deal with it.

Why this is important: I use Tanstack-Start and I do not want to have some Provider for custom React context and stuff like this.

I also wanted to avoid having additional libs for state management because this implies an additional learning curve for the developers.

Here is some example code that just uses the capabilities of Tanstack-Query to implement a context without any additional code needed. My example uses a custom and simple React-Hook but you can use the state anywhere in your app using Tanstack Query standard Api.

Prerequisite: You need to access the Tanstack Query Client by useQueryClient() - but this pattern should be already in place, even in Tanstack-Router (incl. Tanstack-Start).

In this example you can also enrich your context with some data from the server if needed. You could just skip the loadSomethingFromYouApi call if it is not needed.

import { useQuery, useQueryClient } from '@tanstack/react-query'

export const useMyContext = () => {
   const queryClient = useQueryClient()
   const { context, isLoading } = useQuery({
      queryKey: ['MyContext'],
      staleTime: Infinity,
      queryFn: async () => {
         const serverData = await loadSomethingFromYourApi()
         return {
            serverFoo: serverData.foo
            clientStuff: 'from the client'
         }
      }
   })
   return {
      context
      isLoading
      setContext: (updater: (oldContext) => void) => queryClient.setQueryData('MyContext', updater)
   }
}

...and voila: You can use useMyContext like you use any other React-Context within your app incl. some async call to some API if needed (or some createServerFn of Tanstack Start if you have that in place).

An additional benefit would be to use queryClient.invalidateQuery(['MyContext']) if you want to reload stuff from the server as well.

Happy coding,
Michael