skip to Main Content

When I refresh the page (F5) and the app restarts, the AuthActions.login action is dispatched to set the user property in the (ngrx) store.

stateChanged = onAuthStateChanged(getAuth(), (user) => {
    if (user) { this.store.dispatch(AuthActions.login({ user })); }
    else { console.log('USER-LOGGED-OUT'); }
  });

The issue is that for a moment, the app shows the ‘welcome’ page while still fetching the ‘user’ object from the server, and only after that does it navigate to the ‘books’ page.

Is there a way to wait for the ngrx to set the user object before navigating to a path?

‘app.routes.ts’

export const APP_ROUTES: Routes = [
  {
    path: '',
    component: ShellComponent,
    children: [
      {
        path: '', pathMatch: 'full', redirectTo: 'welcome' },
      {
        path: 'welcome',
        loadChildren: async () => (await import('@welcome/feat/welcome')).WELCOME_ROUTES,
      },
      {
        path: '',
        canMatch: [() => inject(Store).select(selectUser).pipe(map((user) => user!!))],
        providers: [provideState(booksFeature),provideEffects(booksEffects)],
        children: [
          {
            path: 'books',
            loadChildren: async () => (await import('@books/feat/books')).BOOKS_ROUTES,
          },
        ],
      },
      {
        path: '**',
        redirectTo: 'welcome',
      },
    ],
  },
];

2

Answers


  1. What I’d probably do in your case is to provide an APP_INITIALIZER function that waits for the server to responds before launching the application.

    You can do by providing the APP_INITIALIZER token in the application boostraping and passing the initializer function in the useFactory property :

    function getAuthUser(auth: AuthService): Promise<any> {
      return firstValueFrom(auth.initAuthUser());
    }
    
    
    bootstrapApplication(AppComponent, {
      providers: [
        // ...
        {
          provide: APP_INITIALIZER,
          useFactory: getAuthUser,
          deps: [AuthService],
          multi: true
        },
      ]
    })
    

    Angular will now wait for the getAuthUser function to resolve before loading the application, you can run additional logic in it to ensure that your AuthStore is correctly populated.

    Login or Signup to reply.
  2. That’s the expected behavior of the code you shared.

    Firebase automatically restores the user’s authentication state when it loads the page. But doing that requires it to call to the server, e.g. to check whether the account has been disabled. While this call is going on, the current user will still be null – and you render that differently.

    The way to solve this, is to store some indication whether you expect a logged in user in the local state that you can check synchronously when the page loads. So:

    1. Write a flag to local storage when the user signs in
    2. Read that flag when the page reloads and use it to display the initial screen
    3. If onAuthStateChanged then shows that the local state was wrong after all, correct the UI

    You may still have a flash in this case, but the chances are much smaller. Firebaser Michael Bleigh explained this technique at Google I/O a few years back, so check that out here: https://www.youtube.com/watch?v=NwY6jkohseg&t=1311s

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search