#Context is not up to date after navigate

7 messages · Page 1 of 1 (latest)

pine ravine
#

Hey guys, I'm trying to handle redirection after login in.

For now, I got my Login Component that is working fine, it updates the AuthContext so I can use my user globally. I would like to be able to redirect my user to /dashboard after the successful login.

My /dashboard route is a protected route, I can access it only if context.useris not null.
But when I'm logging in and trying to redirect, the context is not yet up to date IN THE DASHBOARD ROUTE, so I got redirect back to the login page.

Do anyone have an idea on how to solve this ?

#

Login.tsx

import { login } from '#/api/mutations/auth'
import { AuthContext } from '#/context/AuthProvider'
import { getError, hasError } from '#/utils/errors'
import { Button } from '#components/catalyst/button'
import { ErrorMessage, Field, Label } from '#components/catalyst/fieldset'
import { Input } from '#components/catalyst/input'
import { ApiError } from '#types/error'
import { AuthContextType, LoginPayload, User } from '#types/user'
import { useForm } from '@tanstack/react-form'
import { useMutation } from '@tanstack/react-query'
import { createFileRoute, redirect, useNavigate } from '@tanstack/react-router'
import { enqueueSnackbar } from 'notistack'
import { useContext } from 'react'

export const Route = createFileRoute('/login')({
  beforeLoad: ({ context }) => {
    if (context.user) {
      throw redirect({
        to: '/dashboard',
      })
    }
  },
  component: () => <Login />,
})

const Login = () => {
  const { updateUser } = useContext(AuthContext) as AuthContextType
  const navigate = useNavigate({ from: '/login' })

  const { mutate, isPending, error } = useMutation<
    User,
    ApiError[],
    LoginPayload
  >({
    mutationFn: (payload: LoginPayload) => {
      return login(payload)
    },
    onSuccess: (data) => {
      updateUser(data)
      enqueueSnackbar('Vous êtes connecté', { variant: 'success' })
    },
    onSettled: async () => {
      await navigate({ to: '/dashboard' })
    },
  })

  const form = useForm({
    defaultValues: {
      email: '',
      password: '',
    },
    onSubmit: async ({ value }) => {
      mutate(value)
    },
  })

  return (
    // THE FORM HERE 
  )
}

#

Dashboard.tsx

import { createFileRoute, redirect } from '@tanstack/react-router'

export const Route = createFileRoute('/dashboard')({
  beforeLoad: ({ context, location }) => {
    console.log(context)
    if (!context.user) {
      console.log('redirect')
      throw redirect({
        to: '/login',
        search: {
          redirect: location.href,
        },
      })
    }
  },
  component: () => <div>Hello /dashboard!</div>,
})
#

May be there is something I don't know about context update and update in Tanstack, I'm pretty new to all of this !

Thanks!

ember cloak
#

where does your route context is updated ?

pine ravine
#

it is update through the updateUser function in the onSuccess method from useMutation

The context is given to the route through the routerProvider

import { queryClient } from '#/api/queryClient'
import { AuthContext } from '#/context/AuthProvider'
import { routeTree } from '#/routeTree.gen'
import { RouterProvider, createRouter } from '@tanstack/react-router'
import { useContext } from 'react'
import { AuthContextType } from './types/user'

const router = createRouter({
  routeTree,
  context: {
    queryClient: undefined!,
    user: undefined!,
    updateUser: () => {},
    logout: () => {},
  },
  defaultPreload: 'intent',
  defaultPreloadStaleTime: 0,
})

export default function App() {
  const authContext = useContext(AuthContext) as AuthContextType
  return (
    <RouterProvider router={router} context={{ ...authContext, queryClient }} />
  )
}
#

With this I can access the context directly in the route declaration. This is why I can access the context property on the beforeLoad method