我正在创建一个与 MatPaginator 类似的组件,但使用 ComponentStore遵循此docs它似乎工作得很好,除了 @Output page
在初始化时发出的事实是意外的。预期的行为是仅在用户更改页面时发出,就像在 Material 版本中一样。
这是重要的代码(它与链接的文档相同):
PaginatorStore:
@Injectable()
export class PaginatorStore extends ComponentStore<PaginatorState> {
private readonly pageIndexChanges$ = this.state$.pipe(
map(({ pageIndex }) => pageIndex),
pairwise()
);
readonly page$: Observable<PageEvent> = this.select(
this.pageIndexChanges$,
this.select((state) => [state.pageSize, state.length]),
([previousPageIndex, pageIndex], [pageSize, length]) => ({
pageIndex,
previousPageIndex,
pageSize,
length,
}),
{ debounce: true }
);
}
PaginatorComponent:
@Component({ providers: [PaginatorStore] })
class Component {
@Output() readonly page = this.paginatorStore.page$;
}
请注意,我还打开了 issue在存储库中,但直到现在我才得到任何答案。
最佳答案
ngrx 存储的行为类似于 BehaviorSubject这意味着在订阅时您将始终获得当前状态。一开始,这是您创建商店时设置的初始状态。
如果您想从下一个更改开始,您可以添加 skip运算符并跳过第一个值,这样您将永远不会获得当前状态,而只能接收之后的事件。
@Component({ providers: [PaginatorStore] })
class Component {
@Output() readonly page = this.paginatorStore.page$.pipe(skip(1));
}
对于你的情况,我认为你应该采用更复杂的解决方案,因为 Angular 期望 @Output
属性使用 EventEmitter类型。事件发射器也是 Subject因此您可以直接订阅商店 Observable,并且值将自动传播。
以下是此场景的示例实现。
@Component({ providers: [PaginatorStore] })
class Component implements OnDestroy {
@Output() readonly page = new EventEmitter<PageEvent>();
private destroyed = false;
constructor(private readonly paginatorStore: PaginatorStore) {
this.paginatorStore.page$.pipe(skip(1), takeWhile(() => !this.destroyed)).subscribe(this.page);
}
ngOnDestroy(): void {
this.destroyed = true;
}
}
你可以看到我还添加了一个 OnDestroy实现以防止组件被销毁后保留订阅,因为这可能导致内存泄漏。
这里还有一个指向 fork of your StackBlitz 的链接这样您就可以看到它的实际效果。
关于angular - 如何使用 ngrx/component-store 示例在初始化时不发出事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66233833/