【发布时间】:2017-08-30 05:38:26
【问题描述】:
首先是一些上下文,我正在使用:
- reselect 用于选择器
- normalizr 用于规范化和反规范化
- ngrx/store,是 redux 的响应式实现,用于状态管理
现在类似于react real world example,我有一个专用于实体的状态切片,这实际上是 normalizr 的 denormalize() 方法工作的要求,因为文章可以有一个 author 或 media 可以都是实体本身。
这意味着,例如,当我从我的状态中选择一个 user 时,我正在抓取这个全局实体切片,我的选择器看起来像这样
export const getOne = createSelector(
getAllEntities,
getDetailId,
(entities, id) => denormalize(id, schema, entities)
);
然后从ngrx/store中“选择”
state.map(getOne).distinctUntilChanged()
现在要填写我的表格,我这样做(半伪代码)
class Cmp {
form = new FormGroup({ /* whatever */});
user$ = this._store.map(getOne).distinctUntilChanged();
constructor(private _store: Store<AppState>) {
this.user$.subscribe((data) => {
this.form.patchValue(data);
});
}
}
结合 reselect 和 map/distincUntilChanged 我几乎可以在任何时候任何实体更改时获得新的更新,因此请考虑这种情况..
- 您访问了 id 5 的文章,其中填写了对由全局实体 slice 组成的 store slice 的订阅
- 你开始编辑“
text”FormControl - 其他人更改了 id 为 3 的用户,而您通过 websockets 收到更新,导致
subscribe触发(因为全局实体切片已更改)并覆盖您在编辑时更改的任何值,当前值位于存储(旧值)
..这个 websocket 有很多不同的情况会导致更新更新。
redux 世界中是否有任何模式可以解决这个问题,或者 ngrx 世界中是否有人必须处理这个问题?我想到的唯一明智的事情是在您键入时将任何价值保存到商店,这将需要挂钩角度反应形式来存储,这是一个巨大的痛苦,而且ngrx/forms 不会很快到来。但我敢肯定,一定有人已经想出了一些简单的解决方案。
谢谢!
(你可以阅读gitter的后续讨论)
【问题讨论】:
-
denormalize不是直接访问实体,而不是通过reselect-created 选择器访问实体的问题吗?如果您要使用选择器以更手动的方式进行非规范化,那会解决问题吗?虽然,您显然会失去基于模式的细节。 -
可行的方法是为表单所需的值创建一个额外的选择器(通常是没有关系的原语,即文本),但在某些情况下这仍然存在问题, IE。 (下一条评论)
-
想象你有一个用户的名字和年龄,你至少可以有两种情况 - 你正在编辑名字,没有触及年龄,其他人更新同一个用户并改变年龄..因为你没有'实际上并没有改变它,你希望它更新,否则一旦你在更改名称后按保存,更新的年龄将被更改回更新前的任何值 - 但如果你同时更改了年龄和名称(并且你仍在编辑名称),您不希望将年龄更改为其他人将其更改为的任何值,因为您故意进行了更改并且您希望它是最新值
-
我认为你有两个问题:非规范化问题;和并发编辑问题。使用选择器而不是非规范化可能会解决第一个问题。并且关闭焦点上的输入/属性更新(并在保存后重新打开)可能会解决第二个问题。您可能可以使用
filter来打开/关闭每个输入/属性更新。需要考虑的事情。 -
我认为焦点不够,您可以将多个输入分组在一个保存按钮下.. 但我在想的是实现一个自定义
patchValue函数,只能更新pristine表单控件,假设FormControl上的pristine执行我认为的操作。
标签: angular redux rxjs angular2-forms ngrx