You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular + NgRx:页面刷新时等待user加载完成再导航

解决NgRx Auth状态初始化前路由闪烁问题

页面刷新时Auth状态初始化是异步操作,当前路由默认直接跳转至welcome页面,等Store中user状态更新后才匹配books路由,导致页面短暂闪烁。以下是具体解决方案:

1. 区分Auth状态的“未初始化”与“已登录/未登录”

先修改Auth的State结构,添加标志跟踪Auth是否初始化完成,同时明确user的状态含义:undefined表示未初始化、null表示未登录、用户对象表示已登录:

// auth.reducer.ts
export interface AuthState {
  user: User | null | undefined;
  authLoaded: boolean; // 新增:标记Auth状态是否已初始化完成
}

const initialState: AuthState = {
  user: undefined,
  authLoaded: false,
};

export const authReducer = createReducer(
  initialState,
  on(AuthActions.login, (state, { user }) => ({
    ...state,
    user,
    authLoaded: true,
  })),
  on(AuthActions.logout, (state) => ({
    ...state,
    user: null,
    authLoaded: true,
  }))
);

同时更新Auth状态监听逻辑,未登录时也派发logout动作,确保Auth状态标记为已初始化:

stateChanged = onAuthStateChanged(getAuth(), (user) => {
  if (user) { 
    this.store.dispatch(AuthActions.login({ user })); 
  } else { 
    this.store.dispatch(AuthActions.logout());
  }
});

2. 修改路由逻辑,等待Auth初始化完成后再导航

调整app.routes.ts,让默认路由不再直接跳转welcome,而是等待Auth状态初始化完成后,根据user值决定最终导航目标:

export const APP_ROUTES: Routes = [
  {
    path: '',
    component: ShellComponent,
    children: [
      // 初始空路径:等待Auth初始化完成后再匹配后续路由
      {
        path: '',
        pathMatch: 'full',
        canMatch: [() => inject(Store).select(selectAuthLoaded).pipe(
          filter(loaded => loaded),
          map(() => true),
          first()
        )],
        redirectTo: '',
      },
      // 已登录用户:直接跳转至books页面
      {
        path: '',
        pathMatch: 'full',
        canMatch: [() => inject(Store).select(selectUser).pipe(
          map(user => !!user),
          first()
        )],
        redirectTo: 'books'
      },
      // 未登录用户:跳转至welcome页面
      {
        path: '',
        pathMatch: 'full',
        canMatch: [() => inject(Store).select(selectUser).pipe(
          map(user => user === null),
          first()
        )],
        redirectTo: 'welcome'
      },
      // Welcome页面路由
      {
        path: 'welcome',
        loadChildren: async () => (await import('@welcome/feat/welcome')).WELCOME_ROUTES,
      },
      // 已登录用户的books路由
      {
        path: '',
        canMatch: [() => inject(Store).select(selectUser).pipe(
          map(user => !!user),
          first()
        )],
        providers: [provideState(booksFeature),provideEffects(booksEffects)],
        children: [
          {
            path: 'books',
            loadChildren: async () => (await import('@books/feat/books')).BOOKS_ROUTES,
          },
        ],
      },
      // 404路由
      {
        path: '**',
        redirectTo: 'welcome',
      },
    ],
  },
];

3. 可选:添加初始化加载状态

如果想在Auth初始化期间显示加载动画,可在ShellComponent中监听authLoaded状态,控制内容显示:

// shell.component.ts
authLoaded$ = this.store.select(selectAuthLoaded);

constructor(private store: Store) {}
<!-- shell.component.html -->
<div *ngIf="authLoaded$ | async; else loading">
  <router-outlet></router-outlet>
</div>
<ng-template #loading>
  <div class="loading-spinner">加载中...</div>
</ng-template>

这样页面刷新时会先显示加载状态,等Auth初始化完成后直接导航到对应页面,不会出现welcome页面的短暂闪烁。

内容的提问来源于stack exchange,提问作者pax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 15:48:09