数据更新后,NgRx 如何更新远程数据?
How NgRx updates remote data when the data has been updated?
我无法理解 NgRx 的工作原理。我有一个用户列表,它是通过 Firebase 商店的服务加载的,如下所示:
getAllUsers():Observable<object>{
console.log('getAllUsers');
return this.afs.collection('users', (ref:any) => ref.where("role", '!=', 'admin')).valueChanges();
}
然后我在存储用户列表的模块中有一个商店设置,它工作得很好并且在管理员登录到应用程序时加载用户列表一次,因为它是在仪表板中调度的容器管理路由器插座。其中一部分是管理员可以单击每个用户并更新他们的信息,从而从未连接到商店的服务中触发此功能:
async updateUserData(data:any, id:any){
await this.afs.collection('users').doc(id).update(data);
}
我原以为当用户数据更新时,存储的用户列表在再次下载之前不会更新,但它会相应地更新。
这是怎么回事?我正在记录 getAllUsers 函数,但它没有被再次调用。取而代之的是操作:LoadUsersSuccess 在调用 updateUserData 时被调用,但它们在效果中的任何地方都没有连接。我真的很想知道这是怎么回事,但我在任何地方都找不到答案。这是我的商店设置-
actions.ts:
import { Action } from "@ngrx/store";
export enum AdminActionTypes{
LOAD_USERS = '[ADMIN] Load Users',
LOAD_USERS_SUCCESS = '[ADMIN] Load Users Success',
LOAD_USERS_FAILURE = '[ADMIN] Load Users Failure',
}
export class LoadUsersAction implements Action {
readonly type = AdminActionTypes.LOAD_USERS;
}
export class LoadUsersSuccessAction implements Action {
readonly type = AdminActionTypes.LOAD_USERS_SUCCESS;
constructor(public payload: any){}
}
export class LoadUsersFailureAction implements Action {
readonly type = AdminActionTypes.LOAD_USERS_FAILURE;
constructor(public payload: Error){}
}
export type AdminAction = LoadUsersAction | LoadUsersFailureAction | LoadUsersSuccessAction;
reducer.ts:
import { AdminActionTypes, AdminAction} from './admin.actions';
import { createFeature, createFeatureSelector, createSelector } from '@ngrx/store';
export interface AdminState {
list: any[],
loading: boolean,
error: Error
}
const initialState: AdminState = {
list:[],
loading:false,
error: {name: "", message: ""}
}
export function AdminReducer(
state: AdminState = initialState,
action: AdminAction,
){
switch (action.type){
case AdminActionTypes.LOAD_USERS:
return {...state, loading: true};
case AdminActionTypes.LOAD_USERS_SUCCESS:
return {...state, list:action.payload, loading:false};
case AdminActionTypes.LOAD_USERS_FAILURE:
return {...state, error:action.payload, loading:false};
default:
return state;
}
}
export const getAdminState = createFeatureSelector<AdminState>('admin');
export const loadUsers = createSelector(getAdminState, (state: AdminState) => state.loading);
export const loadUsersSuccess = createSelector(getAdminState, (state: AdminState) => state.list);
export const loadUsersFailure = createSelector(getAdminState, (state: AdminState) => state.error);
effects.ts:
@Injectable()
export class AdminEffects {
loadUsers$ = createEffect(
() => this.actions$
.pipe(
ofType<LoadUsersAction>(AdminActionTypes.LOAD_USERS),
mergeMap(
() => this.adminService.getAllUsers()
.pipe(
map(data => new LoadUsersSuccessAction(data)),
catchError(error => of (new LoadUsersFailureAction(error)))
),
),
),
)
constructor(
private actions$: Actions,
private adminService: AdminService
){}
}
我认为发生这种情况是因为您 return 来自 getAllUsers
的 Observable
会在 Firebase 集合发生变化时发出一个值。然后 returned Observable
通过 mergeMap
与 loadUsers$
效果的 Observable 内部链接,当新值到来时映射到 LoadUsersSuccessAction
动作来自源 Observable (this.adminService.getAllUsers()
),然后 LoadUsersSuccessAction
被调度。
所以如果你想改变这个行为,你需要在第一个值来自 Firebase 集合时立即完成 getAllUsers()
observable,如下所示:
getAllUsers(): Observable<object> {
console.log('getAllUsers');
return this.afs
.collection('users', (ref: any) => ref.where('role', '!=', 'admin'))
.valueChanges()
.pipe(take(1));
}
或者您需要从效果中提取逻辑(从 firebase 获取 valuesChanges
)并在其他地方使用它。
我无法理解 NgRx 的工作原理。我有一个用户列表,它是通过 Firebase 商店的服务加载的,如下所示:
getAllUsers():Observable<object>{
console.log('getAllUsers');
return this.afs.collection('users', (ref:any) => ref.where("role", '!=', 'admin')).valueChanges();
}
然后我在存储用户列表的模块中有一个商店设置,它工作得很好并且在管理员登录到应用程序时加载用户列表一次,因为它是在仪表板中调度的容器管理路由器插座。其中一部分是管理员可以单击每个用户并更新他们的信息,从而从未连接到商店的服务中触发此功能:
async updateUserData(data:any, id:any){
await this.afs.collection('users').doc(id).update(data);
}
我原以为当用户数据更新时,存储的用户列表在再次下载之前不会更新,但它会相应地更新。 这是怎么回事?我正在记录 getAllUsers 函数,但它没有被再次调用。取而代之的是操作:LoadUsersSuccess 在调用 updateUserData 时被调用,但它们在效果中的任何地方都没有连接。我真的很想知道这是怎么回事,但我在任何地方都找不到答案。这是我的商店设置-
actions.ts:
import { Action } from "@ngrx/store";
export enum AdminActionTypes{
LOAD_USERS = '[ADMIN] Load Users',
LOAD_USERS_SUCCESS = '[ADMIN] Load Users Success',
LOAD_USERS_FAILURE = '[ADMIN] Load Users Failure',
}
export class LoadUsersAction implements Action {
readonly type = AdminActionTypes.LOAD_USERS;
}
export class LoadUsersSuccessAction implements Action {
readonly type = AdminActionTypes.LOAD_USERS_SUCCESS;
constructor(public payload: any){}
}
export class LoadUsersFailureAction implements Action {
readonly type = AdminActionTypes.LOAD_USERS_FAILURE;
constructor(public payload: Error){}
}
export type AdminAction = LoadUsersAction | LoadUsersFailureAction | LoadUsersSuccessAction;
reducer.ts:
import { AdminActionTypes, AdminAction} from './admin.actions';
import { createFeature, createFeatureSelector, createSelector } from '@ngrx/store';
export interface AdminState {
list: any[],
loading: boolean,
error: Error
}
const initialState: AdminState = {
list:[],
loading:false,
error: {name: "", message: ""}
}
export function AdminReducer(
state: AdminState = initialState,
action: AdminAction,
){
switch (action.type){
case AdminActionTypes.LOAD_USERS:
return {...state, loading: true};
case AdminActionTypes.LOAD_USERS_SUCCESS:
return {...state, list:action.payload, loading:false};
case AdminActionTypes.LOAD_USERS_FAILURE:
return {...state, error:action.payload, loading:false};
default:
return state;
}
}
export const getAdminState = createFeatureSelector<AdminState>('admin');
export const loadUsers = createSelector(getAdminState, (state: AdminState) => state.loading);
export const loadUsersSuccess = createSelector(getAdminState, (state: AdminState) => state.list);
export const loadUsersFailure = createSelector(getAdminState, (state: AdminState) => state.error);
effects.ts:
@Injectable()
export class AdminEffects {
loadUsers$ = createEffect(
() => this.actions$
.pipe(
ofType<LoadUsersAction>(AdminActionTypes.LOAD_USERS),
mergeMap(
() => this.adminService.getAllUsers()
.pipe(
map(data => new LoadUsersSuccessAction(data)),
catchError(error => of (new LoadUsersFailureAction(error)))
),
),
),
)
constructor(
private actions$: Actions,
private adminService: AdminService
){}
}
我认为发生这种情况是因为您 return 来自 getAllUsers
的 Observable
会在 Firebase 集合发生变化时发出一个值。然后 returned Observable
通过 mergeMap
与 loadUsers$
效果的 Observable 内部链接,当新值到来时映射到 LoadUsersSuccessAction
动作来自源 Observable (this.adminService.getAllUsers()
),然后 LoadUsersSuccessAction
被调度。
所以如果你想改变这个行为,你需要在第一个值来自 Firebase 集合时立即完成 getAllUsers()
observable,如下所示:
getAllUsers(): Observable<object> {
console.log('getAllUsers');
return this.afs
.collection('users', (ref: any) => ref.where('role', '!=', 'admin'))
.valueChanges()
.pipe(take(1));
}
或者您需要从效果中提取逻辑(从 firebase 获取 valuesChanges
)并在其他地方使用它。