TanStackT
TanStack10mo ago
6 replies
unsightly-emerald

Is there a more idiomatic way to do this? Getting Auth Data from Server and Client

So, I am using better auth and Start. I want to eliminate any flicker. that means checking auth status in loaders, but if the user signs out (or signs in) since this is also a SPA, we should use client data as well. That lead me to do the following

in routes/__root.tsx:
export const authStateFn = createServerFn({method: "GET"}).handler(async () => {
  const {headers} = getEvent()
  const data = await auth.api.getSession({headers})
  return data
})

export const Route = createRootRoute({
beforeLoad: async () => { return await authStateFn() },
  loader: async ({context}) => {
    if (!context?.session || !context?.user) return null
    return {
      session: context.session,
      user: context.user
    }
  },
  staleTime: 60_000,
  component: RootComponent,
})


This gets the data into the root loader. since I check auth status on every page (at the very least, to know whether or not to show the sign in or sign out buttons), I set the staleTime to 60 seconds to slow down unnecesary requests to the database

Then I created a custom hook

const isServer = typeof window === "undefined"

export function useAuthData() {
    const {data: clientData, isPending} = useSession()
    const rootRouteApi = getRouteApi("__root__")
    const serverData = rootRouteApi.useLoaderData()
    const serverAuthData = serverData?.session && serverData?.user ? {session: serverData.session, user: serverData.user} : null

    return (isPending || isServer) ? serverAuthData : clientData
}


isPending is annoyingly false on servers, so I have to check if we are in a server context or pending on client data. if that is the case, I use the server data from the root loader above. otherwise, we can use clientData

now I have a flicker free ui, but is there a more idiomatic way to do this?
Was this page helpful?