NgRX 是一个用于 Angular 应用的状态管理库,它基于 Redux 模式。NgRX 实体(Entities)是一种优化 Redux 状态管理的方式,特别适用于处理大量相似的对象,如列表数据。
实体标准化是将 API 响应转换为一种标准化的格式,以便更容易地在应用中管理和查询这些数据。标准化的格式通常包括两个部分:
ids
: 一个包含所有实体 ID 的数组。entities
: 一个对象,键是实体 ID,值是实体的详细信息。NgRX 实体库提供了几种主要的操作类型:
loadSuccess
: 成功加载实体数据。addSuccess
: 成功添加新实体。updateSuccess
: 成功更新现有实体。deleteSuccess
: 成功删除实体。假设我们有一个 API 响应如下:
{
"users": [
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
]
}
我们可以使用 NgRX 实体来标准化这个响应:
首先,定义一个实体适配器:
import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity';
export interface User {
id: number;
name: string;
email: string;
}
export interface UsersState extends EntityState<User> {}
export const usersAdapter: EntityAdapter<User> = createEntityAdapter<User>();
然后,创建一个 reducer 来处理 API 响应:
import { createReducer, on } from '@ngrx/store';
import { usersAdapter } from './users.adapter';
import { loadUsersSuccess } from './users.actions';
export const initialState: UsersState = usersAdapter.getInitialState();
const usersReducer = createReducer(
initialState,
on(loadUsersSuccess, (state, { users }) => usersAdapter.setAll(users, state))
);
export function reducer(state: UsersState | undefined, action: Action) {
return usersReducer(state, action);
}
定义相应的 actions:
import { createAction, props } from '@ngrx/store';
export const loadUsersSuccess = createAction(
'[User] Load Users Success',
props<{ users: User[] }>()
);
最后,在组件中使用这些状态:
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { selectAllUsers } from './users.selectors';
@Component({
selector: 'app-user-list',
template: `
<ul>
<li *ngFor="let user of users$ | async">{{ user.name }} - {{ user.email }}</li>
</ul>
`
})
export class UserListComponent implements OnInit {
users$: Observable<User[]>;
constructor(private store: Store) {}
ngOnInit() {
this.users$ = this.store.select(selectAllUsers);
}
}
问题:为什么标准化后的数据在某些情况下没有更新?
原因:可能是由于选择器(Selectors)没有正确地检测到状态的变化。
解决方法:确保使用 createSelector
来创建记忆化的选择器,并且在 reducer 中正确地更新状态。
import { createSelector } from '@ngrx/store';
import { UsersState } from './users.reducer';
export const selectUsersState = (state: any) => state.users;
export const selectAllUsers = createSelector(
selectUsersState,
(state: UsersState) => state.ids.map(id => state.entities[id])
);
通过这种方式,可以确保只有当相关实体发生变化时,选择器才会返回新的值。
领取专属 10元无门槛券
手把手带您无忧上云