【问题标题】:How to fix subscription leak Angular ngrx store如何修复订阅泄漏 Angular ngrx 商店
【发布时间】:2019-03-21 23:03:45
【问题描述】:

我有一个 ponyracer 应用程序,它实现了 ngrx 商店。非常基本的功能:开始比赛,添加小马,删除小马,分数表。当我删除或添加小马时,问题就出现了——基本上这个功能是指创建或销毁小马组件。因此,任何添加的 Pony 都出于某种原因存储在某处,即使在销毁组件之后 - 应用程序仍然可以访问所有添加和删除的小马,并迭代它们,例如当我只需要查看现有小马的分数时 - 但所有(甚至以前已移除)显示小马

我用的是store.select.pipe(...).subscribe(),不用onDestroy和unsubscribe()

races.component.ts

export class RacesComponent implements OnInit {
    racesState: Observable<fromPonyRacer.State>;

    constructor(private store: Store<fromApp.AppState>) { }

    ngOnInit() {
        this.racesState = this.store.select("raceList");
        this.racesState.subscribe()
    }
}

races.component.html

<pr-race *ngFor="let race of (racesState | async).races; let i = index" 
         [race]="race" [index]="i"> 
</pr-race>

race.component.ts

export class RaceComponent implements OnInit {
    @Input() race: RaceModel;
    @Input() index: number;
    racesState: Observable<fromPonyRacer.State>;

    constructor(private store: Store<fromApp.AppState>) { }

    ngOnInit() {
    this.racesState = this.store.select("raceList");
    this.racesState.pipe(
        tap(races => {
            if(races.raceStatus) this.movePony();
        })
    )
    .subscribe()
    }
}

race.component.html

<div class="race">
    <img class="pony-img" [src]="race.src"> 
</div>

当小马完成时,将调度动作并将小马添加到名为 currentRaces 的存储属性中,因此存储跟踪哪个小马先完成,第二个完成,依此类推。

const initialState: State = {
    races: [
        new RaceModel(some data),
        new RaceModel(some another data),
        new RaceModel(some more data)
      ],
    raceStatus: false,
    raceCount: 0,
    isNewrace: false,
    poniesAreAboutToFinish: null,
    currentRaces: []
}

但是这个动作也会被移除的小马调度,它们也会到达 store.currentRaces 并显示在分数表中。而且我无法弄清楚这些被移除的小马是从哪里来的。因为 state.races 总是真实的和正确的(根据 redux 开发工具),而races.component 需要 state.races 为每个小马渲染视图,它总是正确和新鲜的

movePony() {
    some code for moving a pony
      if(ponyReachedFinish) {
      this.store.dispatch(new PonyRacerActions.StopRace({name: this.race.name, place, points})
    }
}

如果需要更多详细信息,您可以在此处找到完整代码:https://github.com/joistick1/pr2

更新:问题已解决。正如我最初假设的那样,问题是由于订阅泄漏而发生的。我应用了 OnDestroy 并在此方法中应用了一行代码 this.subscription.unsubscribe();

【问题讨论】:

  • 如果你在 hot observables 上使用 subscribe,为什么是 there is no need to use onDestroy and unsubscribe() ?这应该是强制性的。
  • 我第二个@trichetriche。如果您要从商店订阅 observable,您需要使用 async 管道进行订阅,或者在组件中显式调用 .unsubscribe()
  • @trichetriche 流是 hot 的事实与问题并不真正相关,而流是 infinite 是它的原因。跨度>
  • 是的,尽管订阅 Observable 是一种不好的做法,但它绝对不是错误的原因。将你的 reducer 代码贴在你移除小马的地方。
  • @Jota.Toledo 无论是异步管道订阅 Observable,还是您在组件中订阅都不会改变发出的值。很明显,他的错误出在他的 reducer 中,这实际上决定了他的应用程序的状态。

标签: angular ngrx ngrx-store


【解决方案1】:

在您的 reducer 中,当您删除小马时,您会直接改变状态,而不是返回新的不可变状态。尝试应用以下更改:

case PonyRacerActions.DELETE_PONY:
            return {
                ...state,
                races: state.races.filter(race => race != action.payload),
                currentRaces: []
            }

【讨论】:

  • 试过这种方式更新reducer,但仍然面临同样的问题。删除小马 -> 开始比赛 -> 仍然在分数表中看到已删除的小马
猜你喜欢
  • 1970-01-01
  • 2022-10-21
  • 2019-03-06
  • 2019-08-18
  • 1970-01-01
  • 2018-02-16
  • 2020-03-26
  • 2018-04-02
  • 2019-06-12
相关资源
最近更新 更多