【问题标题】:Routing between two components removes subscription from NGRX store两个组件之间的路由从 NGRX 存储中删除订阅
【发布时间】:2020-08-15 12:57:23
【问题描述】:

我的应用程序中有两个页面DashboardTransactions 以及一个控制导航的Sidebar 组件。

当我第一次从Dashboard 导航到Transactions 时,我订阅了商店中的用户状态。一切都按预期工作,我获取了用户 ID 并将其注入到子组件中以使用。

export class TransactionsComponent implements OnInit {
  userID;

  constructor(private store: Store<AppState>, private spinner: NgxSpinnerService) {}

  ngOnInit() {
    this.spinner.show();
    this.store.select('user').subscribe(
      user => { if (user) { this.userID = user.uid; } }
    );
  }
}

当我导航回Dashboard 页面,然后返回Transactions 页面时,我遇到了用户ID 永远无法解析和无休止的加载微调器。

在我的Sidebar 中,从交易页面导航到仪表板时,此订阅会消失。

export class SidebarComponent implements OnInit {
  user$: Observable<User>;

  constructor(public auth: AuthService, private store: Store<AppState>) {}

  ngOnInit(): void {
    this.user$ = this.store.select('user');
    this.store.dispatch(new userActions.GetUser());
  }
}

这是我将检索用户 ID 的效果

  @Effect()
  getUser: Observable<Action> = this.actions.pipe(
    ofType(userActions.GET_USER),
    map((action: userActions.GetUser) => action.payload ),
    switchMap(payload => this.afAuth.authState),
    delay(2000), // delay to show loading spinner can be deleted
    map( authData => {
        if (authData) {
          // User logged in
          const user = new User(authData.uid, authData.displayName);
          return new userActions.Authenticated(user);
        } else {
          return new userActions.NotAuthenticated();
        }
    }),
    catchError(err => of(new userActions.AuthError()) )
  );

我希望Transactions 组件能够保持用户 ID 的状态,并且在我返回时不需要加载微调器。

【问题讨论】:

  • 您实现了一个全局状态解决方案,因此您的组件不必记住用户 ID。这是商店的任务。如果您没有在其他任何地方覆盖商店中的用户,您应该在您的问题中发布更多代码,因为您粘贴在那里的内容对我来说看起来很正常。你认为有可能在stackblitz.com 上建立最小复制吗?
  • 好的,我在从交易页面导航到仪表板页面时订阅消失的地方添加了更多代码。我还添加了名为 GetUser 的效果来检索用户。这可能是问题的一部分吗?
  • 不..没什么奇怪的......也许在减速器逻辑中?此外,在组件逻辑中,您将在 OnInit 挂钩上启动微调器。你在哪里阻止它? Stackblitz 演示对您有帮助 ;)
  • TransactionsComponent 中,我认为您需要在ngOnInit() 中调度您的一项操作以获取用户this.store.dispatch(YourUserActions.Load())

标签: angular typescript angular-routing ngrx


【解决方案1】:

您在 SidebarComponentuser$ 中拥有正确的代码 - 只需创建一个 Observable 而不是 subscription

TransactionsComponent 中您需要使用相同的模式,是否有理由将用户userID 保留为独立属性?

我会建议你下一个方法。

export class TransactionsComponent implements OnInit {
  userId$;

  constructor(private store: Store<AppState>, private spinner: NgxSpinnerService) {}

  ngOnInit() {
    this.userId = this.store.select('user').pipe(
      tap(user => {
        if (user) { // we've got a use, the data has been loaded
          this.spinner.hide();
        } else {
          this.spinner.show(); // no user - looks like the loading is in progress
        }
      }),
      map(user => user ? user.uid : undefined),
      filter(userId => userId !== undefined), // <- comment in case userId isn't required.
    );
  }
}

然后在它的模板中

<ng-container *ngIf="userId$ | async as userId">
   <child-component [userId]="userId"></child-component>
</ng-container>

【讨论】:

  • 我将它作为一个独立的属性作为输入传递给子组件。我有一个添加事务组件,我希望在您添加事务时使用此 ID。
  • 如果你进一步传递它 - 为什么你不想在其模板中使用 async 管道而不是订阅?
  • 我已经用一个示例更新了我的答案,该示例如何通过async 管道传递给其他组件。
  • 感谢您的快速响应 - 我已经尝试过您的解决方案,但是现在只要我从仪表板导航到交易页面,用户状态就会立即从商店中消失。我可以看到我在侧边栏中显示的用户 ID 消失了
  • 你能分享dashboard模板的代码吗? spinner 服务背后有什么东西吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 2018-08-01
  • 2023-03-18
  • 1970-01-01
  • 2020-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多