Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context not getting updated in beforeload of router #1604

Closed
PR4SAN opened this issue May 16, 2024 · 9 comments
Closed

Context not getting updated in beforeload of router #1604

PR4SAN opened this issue May 16, 2024 · 9 comments
Labels
question This issue is about a user needing insight

Comments

@PR4SAN
Copy link

PR4SAN commented May 16, 2024

Describe the bug

Followed the same example of the protected route from the documentation.

// main.tsx

import ReactDOM from 'react-dom/client'
import  {Suspense} from 'react'
import {RouterProvider, createRouter} from '@tanstack/react-router'
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
import {Amplify} from 'aws-amplify';
import awsmobile from "../aws-exports.ts";
import './index.css'
import {routeTree} from "./routeTree.gen";
import {AuthProvider, useAuth} from "@/auth.tsx";
import {Toaster} from "@/components/ui/toaster"


Amplify.configure(awsmobile);

export const queryClient = new QueryClient();

const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  context: {
    auth: undefined!,
  },
})

declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router
  }
}

function InnerApp() {
  const auth = useAuth();
  return <RouterProvider router={router} context={{auth}}/>
}

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AuthProvider>
        <Suspense fallback={<div>Loading...</div>}>
        <InnerApp/>
        </Suspense>
        <Toaster/>
      </AuthProvider>
    </QueryClientProvider>
  )
}


const rootElement = document.getElementById("root")!;

if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(<App />);
}

// auth.tsx

import * as React from 'react';
import {useQuery} from "@tanstack/react-query";
import {getCurrentUser} from 'aws-amplify/auth';

export interface AuthContext {
    isAuthenticated: boolean;
    user: any | null;
    isLoading: boolean;
    error: Error | null;
}

const AuthContext = React.createContext<AuthContext | null>(null)

export const useAuthQuery = () => {
    return useQuery({
        queryKey: ['auth'],
        queryFn: async () => {
            try {
                return await getCurrentUser();
            } catch (error) {
                return null;
            }
        },
        queryOptions:{
            retry: false,
            refetchOnWindowFocus: false,
        }

    });
};

export function AuthProvider({ children }: { children: React.ReactNode }) {
    const { data: user, isLoading, error } = useAuthQuery();
    const isAuthenticated = !!user
    const contextValue = { isAuthenticated, user, isLoading, error }
    console.log(contextValue,  'iniital load everything null/false but after fetch gets updated');

    return (
        <AuthContext.Provider value={{...contextValue}}>
            {children}
        </AuthContext.Provider>
    )
}

export function useAuth() {
    const context = React.useContext(AuthContext)
    if (!context) {
        throw new Error('useAuth must be used within an AuthProvider')
    }
    return context
}


// _auth.tsx

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

export const Route = createFileRoute('/_authenticated')({
    beforeLoad: async ({ context, location }) => {
        console.log( context, 'initial load same as auth.tsx but doesn't get updated here after data loads')
        if (!context.auth.isAuthenticated) {
            throw redirect({
                to: '/login',
                search: {
                    redirect: location.href,
                },
            })
        }
    },
    component: AuthLayout,
})

function AuthLayout() {
    return (
        <div className="p-2 h-full">
            <h1>Authenticated Route</h1>
            <p>This route's content is only visible to authenticated users.</p>
            <hr />
            <Outlet />
        </div>
    )
}


// __root.tsx

import {
  createRootRouteWithContext, Outlet,
} from '@tanstack/react-router'
import {TanStackRouterDevtools} from '@tanstack/router-devtools'
import {ReactQueryDevtools} from "@tanstack/react-query-devtools";
import {AuthContext} from "@/auth.tsx";


interface RouterContext {
  auth: AuthContext
}

export const Route = createRootRouteWithContext<RouterContext>()({
  component: () => (
    <>
      <Outlet/>
      <ReactQueryDevtools buttonPosition="top-right"/>
      <TanStackRouterDevtools position="bottom-right"/>
    </>
  ),
})

Your Example Website or App

na

Steps to Reproduce the Bug or Issue

followed the same protected route example from doc but the context value for router is not getting updated

Expected behavior

context value should get updated.

Screenshots or Videos

No response

Platform

  • OS: [e.g. macOS, Windows, Linux]
  • Browser: [e.g. Chrome, Safari, Firefox]
  • Version: [e.g. 91.1]

Additional context

No response

@schiller-manuel
Copy link
Contributor

could you please provide this as a complete example on stackblitz (e.g. by forking one of the existing examples)?

@SeanCassiere SeanCassiere added the information needed Further information is requested label May 17, 2024
@PR4SAN
Copy link
Author

PR4SAN commented May 17, 2024

https://stackblitz.com/~/github.com/PR4SAN/tanstack-router

i have tried to make a version of my project removing all the details.

let me know if additional details needed.

This one from documentation where i modified some routes and some implementation to have data fetched as async and this works fine. if i am logged in and i navigate to login it redirects me to dashboard and and vice versa.
https://codesandbox.io/p/devbox/elastic-bessie-thrywl?file=%2Fsrc%2Fauth.tsx%3A8%2C3-8%2C9

@schiller-manuel
Copy link
Contributor

schiller-manuel commented May 17, 2024

https://stackblitz.com/~/github.com/PR4SAN/tanstack-router

which steps are required to reproduce?

please also update to the latest @tanstack/react-router version to check if the issue still exists there

@cpakken
Copy link

cpakken commented May 18, 2024

I think we ran into the same bug, I made a repo that reproduces it:
https://github.com/cpakken/issue-tanstack-router-layout-route-context

#1618

@PR4SAN
Copy link
Author

PR4SAN commented May 18, 2024

which steps are required to reproduce?

  • navigate to dashboard page it redirects to login page even though user is returned as logged in after the promise resolves. also navigate to login page it should redirects to dashboard once promise resolve as it happens the other example.
  • also please check the console logs.
  • i have observed this as issue. so on initial load when everything is null first context at auth.tsx getting set and same values passed to _auth.tsx but after that when auth values changes after promise resolves the context values are not getting passed/updated to _auth.tsx router context. moreover the _auth.tsx file itself not getting executed.

please also update to the latest @tanstack/react-router version to check if the issue still exists there

I have checked with updating the version didn't fix the issue in my project. i have updated it in stackblitz example as well.

@PR4SAN
Copy link
Author

PR4SAN commented May 18, 2024

I think we ran into the same bug, I made a repo that reproduces it: https://github.com/cpakken/issue-tanstack-router-layout-route-context

#1618

yes this is the same issue I am facing as well.

@cpakken
Copy link

cpakken commented May 18, 2024

@tannerlinsley just released v1.32.16 30 minutes ago and fixes #1618 issue. Please check if this issue is resolved

@SeanCassiere
Copy link
Contributor

SeanCassiere commented May 18, 2024

@PR4SAN The issue you are facing is because your router context is not being updated after the useQuery has finished its fetch.

You can either:

  1. call router.invalidate() after fetching
  2. or not render the <RouterProvider /> until the fetch has completed (like in image below).
image

You may also want to check out the authenticated routes example, where their concepts are put to use. Just remember, that you need to take the concepts and adapt it to work with your auth flow. Auth is not static, with every project implementing it just a little bit different from the next.
https://tanstack.com/router/latest/docs/framework/react/examples/authenticated-routes

@PR4SAN
Copy link
Author

PR4SAN commented May 18, 2024

Thanks. Invalidating the router and updating it to the latest version fixed my issue. Also, I noticed the example in the doc is updated. Thanks

@PR4SAN PR4SAN closed this as completed May 18, 2024
@SeanCassiere SeanCassiere added question This issue is about a user needing insight and removed information needed Further information is requested labels May 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question This issue is about a user needing insight
Projects
None yet
Development

No branches or pull requests

4 participants