【发布时间】:2021-03-25 17:36:40
【问题描述】:
Angular v10、NGRX v10
我有一个 Plan 对象,它的一个属性是一个 Task 对象数组。在我的 TaskService 中,我对我的 Plan 对象进行了深度克隆(lodash),更新了我的 Tasks 中的一些属性,然后调度了一个 Action 来更新我的 Store 中的 Plan。奇怪的是,当我在 Reducer 中 console.log(action.payload) 时,Task 属性已恢复为原始值!看了四天,我就是看不到它。
通过在甘特图上拖动一个任务来启动该过程,然后调用 TaskService.updateTasks(tasksToUpdate) 传递任何在用户交互后发生更改的任务。
我在我的 TaskService 中创建了一个非常简化的 updateTasks 方法版本,但我仍然遇到同样的问题。我的简化updateTasksSimple方法如下:
public updateTasksSimple(tasks: ITask[]): void {
const updatedPlan: IPlan = this.coreDataService.cloneDeep(this.currentPlanWithChildren);
const updatedTasks: ITask[] = this.coreDataService.cloneDeep(tasks);
const tasksToUpdate = updatedTasks.filter(t => t.state !== objectState.Unchanged);
// Check we have a tasksToUpdate object.
if (tasksToUpdate !== null) {
// Ensure we have some Tasks to update.
if (tasksToUpdate.length > 0) {
// Logging
tasksToUpdate.forEach(t => {
if (t.state !== objectState.Unchanged) {
console.log(`Updating Task - ${t.title}, Summary: ${t.summary}, Start: ${t.start}, End: ${t.end}, Duration: ${t.durationHours}, Constraint: ${t.taskConstraintType.name}`);
}
});
// Map updated tasks
updatedPlan.tasks = tasksToUpdate.map((t: ITask) => ({
...t,
start: new Date(2021, 2, 26, 16),
end: new Date(2021, 2, 26, 22),
durationHours: 6,
}));
// Logging
console.log(`updateTasksSimple Tasks before dispatch:`);
updatedPlan.tasks.forEach(t => {
console.log(`${t.title}, start: ${t.start}, end: ${t.end}, durationHours: ${t.durationHours}, constraint: ${t.taskConstraintType.name}`);
})
// Dispatch an Action to update the Store.
this.store.dispatch(new planActions.SetCurrentPlanWithChildren(updatedPlan));
}
}
}
我的Action定义如下:
export class SetCurrentPlanWithChildren implements Action {
readonly type = PlanActionTypes.SetCurrentPlanWithChildren;
constructor(public payload: IPlan) { }
}
我按如下方式发送我的操作:
private dispatchUpdate() {
// Logging
console.log(`dispatchUpdate called. Tasks:`);
this.updatedPlan.tasks.forEach(t => {
console.log(`${t.title}, start: ${t.start}, end: ${t.end}, durationHours: ${t.durationHours}, constraint: ${t.taskConstraintType.name}`);
})
this.store.dispatch(new planActions.SetCurrentPlanWithChildren(this.updatedPlan));
};
如您所见,我正在临时记录任务以准确查看我从 TaskService 调度的内容,这里一切正常。
我的 Reducer 如下:
case PlanActionTypes.SetCurrentPlanWithChildren:
console.log(`PlanActionTypes.SetCurrentPlanWithChildren.`, action.payload);
return {
...state,
currentPlanWithChildren: action.payload,
error: ''
};
此处记录的有效负载具有我的 TaskService 进行更改之前的原始值。因此,当我导航到订阅以下选择器的组件时:
export const getCurrentPlanWithChildren = createSelector(
getPlanFeatureState,
(state: PlanState) => state.currentPlanWithChildren
);
它不显示更新的值。我很有可能在这里遗漏了一些明显的东西,但我看不到。非常欢迎任何意见或建议。
更新
在进一步调查中,我观察到以下情况:我的应用有 2 个页面;甘特图和任务。如果我导航到甘特图页面并调用我的updateTasksSimple 方法,它会更改我的任务上的start、end 和duration 属性并分派一个操作来更新商店,如上所述。如果我然后导航到订阅 Store 的任务页面,那么 observable 收到的初始任务是旧值。但是,如果我重新加载应用程序,导航到 Gantt 页面并调用我的 updateTasksSimple 方法 TWICE 然后导航到 Tasks 页面并查看我的 console.log (在 observable 上使用 rxjs tap)收到的初始任务是新的价值观。
就好像我的 observable 接收到的初始值是旧值,而不是 Store 中的当前值。我的任务页面声明我的 observable 如下:
...
public currentPlanWithChildren$: Observable<IPlan>;
...
ngOnInit() {
// Log the Tasks when the CurrentPlanWithChildren changes.
this.currentPlanWithChildren$ = this.store.pipe(select(fromPlan.getCurrentPlanWithChildren)).pipe(
tap(currentPlanWithChildren => {
if (currentPlanWithChildren != null) {
console.log(`PlanTasksContainerComponent.currentPlanWithChildren changed.`);
currentPlanWithChildren.tasks.forEach(t => {
console.log(`Task - ${t.title}, Summary: ${t.summary}, Start: ${t.start.toString()}, End: ${t.end.toString()}, Duration: ${t.durationHours.valueOf()}, Constraint: ${t.taskConstraintType.name}`);
})
}
})
);
}
很奇怪。
【问题讨论】:
-
能否提供TaskService的代码?以及如何以及何时调用
dispatchAction()方法? -
好评。我在
TaskService中重新访问了我的方法并大大简化了它,硬编码了一些日期和持续时间。仍然当我在调度前记录任务时,它们与预期的一样,但在 Reducer 中它们是不正确的! -
这真是奇怪的行为。再一次,您是否尝试过 Web 浏览器中的 Redux Dev Tools?您可能会注意到那里发生了一些奇怪的事情。
标签: angular typescript ngrx