NgRx,一个基于 RxJS 的 Angular 反应式扩展平台,发布了它的第 10 个主要迭代版本,包含了一个用于本地状态管理的新组件存储包。新包对用于应用程序状态管理的 NgRx 存储进行了扩展。此外,一个新的实验性 NgRx 组件包为开发人员开发 Angular 无分区应用程序提供支持,它利用了 Angular Ivy 的能力,以此来获得更好的性能。
Brandon Roberts 在 NgRx 的发布说明中解释了新的本地组件存储所带来的价值:
NgRx Store 用于在全局应用程序级别管理来自多个不同来源的复杂状态。在某些情况下,用户希望以统一的方式在本地管理状态,不需要间接的操作、reducer 和 effects。我们设计了一个新的包来处理本地级别的状态,同时提供与 NgRx Store 类似的好处。
NgRx 应用程序的架构围绕着四个关键概念,这些概念让人联想到 Redux 或 Elm 的架构。动作会捕获事件,无论事件是来自用户或来自其他接口系统(例如套接字或 REST 服务器):
import { createAction, props } from '@ngrx/store';
export const login = createAction(
'[Login Page] Login',
props<{ username: string; password: string }>()
);
复制代码
事件处理器通常分派用户触发的动作(即上述代码示例中的 login):
onSubmit(username: string, password: string) {
store.dispatch(login({ username: username, password: password }));
}
复制代码
应用程序级别的 NgRx Store 通过更新其内容(即应用程序级别的状态)或调度 NgRx effects 来处理分派的操作。这种行为与反应式系统的基本方程是一致的。
顶层状态容器可以帮助开发人员创建可维护的显式应用程序,所有的状态更新都可以追溯到触发事件。这实际上是 Redux 的 promise。
然而,在很多情况下,特别是在具有大量小组件且作用域很小的应用程序中,开发人员使用的组件是读取和更新特定状态的唯一组件。这些状态通常与特定组件的生命周期相关联,并且在组件被销毁时失效。因此,新的 NgRx 组件存储允许开发人员创建在本地处理这些状态片段的组件——本地状态。
发布说明里写道:
ComponentStore 是一个独立的用于管理本地/组件状态的库,是响应式推送的替代方法。
组件存储可以在定义存储时直接初始化:
export interface MoviesState {
movies: Movie[];
}
@Injectable()
export class MoviesStore extends ComponentStore<MoviesState> {
constructor() {
super({movies: []});
}
}
复制代码
组件存储也可以在创建组件时使用 setState 方法来初始化:
@Component({
template: `
<li *ngFor="let movie of (movies$ | async)">
{{ movie.name }}
</li>
`,
providers: [ComponentStore],
})
export class MoviesPageComponent {
readonly movies$ = this.componentStore.state$.pipe(
map(state => state.movies),
);
constructor(
private readonly componentStore: ComponentStore<{movies: Movie[]}>
) {}
ngOnInit() {
this.componentStore.setState({movies: []});
}
}
复制代码
组件存储提供了 select 和 updater 方法来读取本地状态,类似于功能透镜。setState 方法用来更新和替换整个本地状态。最后,effect 方法可以在可观察的管道内运行 effects:
@Injectable()
export class MoviesStore extends ComponentStore<MoviesState> {
constructor(private readonly moviesService: MoviesService) {
super({movies: []});
}
// 每次调用getMovie(id)都会将当前ID推送到movieId$流中。
readonly getMovie = this.effect((movieId$: Observable<string>) => {
return movieId$.pipe(
// 处理竞态条件。
switchMap((id) => this.moviesService.fetchMovie(id).pipe(
// 在内部管道处理结果。
tap({
next: (movie) => this.addMovie(movie),
error: (e) => this.logError(e),
}),
// 在内部管道处理潜在的错误。
catchError(() => EMPTY),
))
);
})
readonly addMovie = this.updater((state, movie: Movie) => ({
movies: [...state.movies, movie],
}));
selectMovie(movieId: string) {
return this.select((state) => state.movies.find(m => m.id === movieId));
}
}
复制代码
可以通过 npm 来安装新的组件存储:
npm install @ngrx/component-store --save
复制代码
或者使用 Angular CLI 来安装:
ng add @ngrx/component-store@latest
复制代码
NgRx 10 还提供了一个实验性的 NgRx 组件包。发布说明里写道:
随着 Ivy 的不断发展,我们需要重新思考如何处理 Angular 无分区应用程序中的反应式。async 管道为 Angular 应用程序处理模板中的可观察对象和 promise 设置了一个标准。NgRx 组件进一步帮你构建完全反应式的应用程序,帮你使用模板中的可观察对象进行渲染。NgRx 组件让我们看到了构建反应式 Angular 应用程序的新方法。
实验包提供了两个指令 ngrxLet 和 ngrxPush,文档中分别对它们进行了解释。
Angular 无分区应用程序在处理变化检测时无需依赖 Angular 无分区机制,这样可能会提高运行时性能。Angular Ivy 和提前编译为此提供了新的可能性。
NgRx 采用了 MIT 许可。欢迎开发者参与贡献,并请遵循贡献指南。
原文链接:
Reactive Angular Library NgRx v10 Adds Component Local State Management Package
评论