NGXS全球状态在每个导航上发出的切片

发布于 2025-01-22 11:08:07 字数 1376 浏览 0 评论 0原文

在追踪意外请求后,我发现我的应用程序的全局用户状态在每个导航时都会发出。

ngxs状态切片的潜在原因是什么

  1. 是发出数据没有更改并且
  2. 没有派遣动作的

这是应用程序中事件的时间顺序

  1. oninit
  2. slice emits emits emits emits - >使用params< - 预期
  3. 用户单击以导航到新页面
  4. UserState选择器发射 - >使用参数< - 意外的
  5. Ondestroy

显然,我们不希望切片在数据中没有更改。

#4演示了触发不必要请求的副作用。

代码

  @Selector()
  public static scope(state: DataModel) {
    console.log('scope triggered');
    return state.scope;
  }

  // Actions only trigger once as expected
  @Action(GetScopes)
  getAvailableScopes(ctx: StateContext<DataModel>) {
    return this.apiService.get('/scopes').pipe(
      tap((result) => {
        ctx.setState(
          patch<DataModel>({
            scope: result.scopes,
          })
        );
      })
    );
  }

这是该应用程序并不复杂的 ,但我无法复制在 stackblitz github

earje应当指出,状态不会更改!

ngxsonchanges(更改:ngxsssimplechange){...仅在应用程序INITS INITS且在此流中再也不会在该流中触发,尽管该州的选择者在此流中都不会触发。在导航上发射。

After tracking down unexpected requests being made I've found that my app's global user state's slices emit upon every navigation.

What are potential causes of an NGXS state slice

  1. emitting where its data hasn't changed and
  2. actions have not been dispatched

Here is the chronological order of events in the app

  1. OnInit
  2. slice emits -> fetch with params <-- EXPECTED
  3. user clicks to navigate to a new page
  4. UserState selectors emit -> fetch with params <-- UNEXPECTED
  5. OnDestroy

Obviously we don't want slices to emit for no changes in data.

#4 demonstrates a side-effect where an unnecessary request is triggered.

Here is the code

  @Selector()
  public static scope(state: DataModel) {
    console.log('scope triggered');
    return state.scope;
  }

  // Actions only trigger once as expected
  @Action(GetScopes)
  getAvailableScopes(ctx: StateContext<DataModel>) {
    return this.apiService.get('/scopes').pipe(
      tap((result) => {
        ctx.setState(
          patch<DataModel>({
            scope: result.scopes,
          })
        );
      })
    );
  }

The app is not complex but I cannot replicate unexpected slices emitting in StackBlitz Github issue

It should be noted that the state does not change!

ngxsOnChanges(change: NgxsSimpleChange) { ... only fires when the app inits and is never again triggered within in this flow despite the state's selectors emitting on navigation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

2025-01-29 11:08:07

上面问题的答案是,国家管理具有几个弱点,您的体系结构将必须监视这些弱点。

其中之一是,对选择器的新订阅会导致选择器发出。

导航到应用程序中的新路由可以加载另一个功能模块。该功能模块订阅了同一选择器,尽管即将取消订阅,但导致旧订阅发出的旧订阅。

我们通过设置解析器来确保所有全球状态都已获取并可用于每个组件来解决此问题。那么这些全球共享的状态就没有时机问题,可以在不订阅它们的情况下使用。

解析器的

@Injectable({ providedIn: 'root' })
export class AppShellResolver implements Resolve<unknown> {
  constructor(private store: Store) {}
  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    return this.store
      .dispatch([
        new GetAvailableScopes(),
        ... <-- other required states for UI
      ])
      ...
  }
}

使用

this.scopes = this.store.selectSnapshot(UserState.scopes);

The answer to the issue above is that state management has several weaknesses which your architecture will have to monitor.

One of them being that new subscriptions to selectors cause the selector to emit.

Navigating to a new route in the app can load another feature module. That feature module subscribes to the same Selectors causing the old subscriptions to emit despite the fact that they are about to be unsubscribed.

We solved this by setting up a resolver to ensure that all global states have been fetched and are available to every component. Then these globally shared states don't have the timing issues and can be used without subscribing to them.

resolver

@Injectable({ providedIn: 'root' })
export class AppShellResolver implements Resolve<unknown> {
  constructor(private store: Store) {}
  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    return this.store
      .dispatch([
        new GetAvailableScopes(),
        ... <-- other required states for UI
      ])
      ...
  }
}

usage

this.scopes = this.store.selectSnapshot(UserState.scopes);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文