首先是一些上下文,我正在使用:
- reselect对于选择器
- normalizr用于规范化和非规范化
- ngrx/store ,这是 redux 的响应式(Reactive)实现,用于状态管理
现在类似于 react real world example我有一片专用于实体的状态,这实际上是 normalizr 的 denormalize()
方法工作的要求,因为文章可以有 author
或 媒体
,它们本身都可以是实体。
这意味着,例如,当我从我的状态中选择单个 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,它被填充为订阅由全局实体切片组成的商店切片
- 开始编辑“
text
”FormControl
- 其他人更改了 id 为 3 的用户,您通过 websockets 收到更新,导致
subscribe
触发(因为全局实体切片已更改)并覆盖您在编辑时更改的任何值,值为当前在商店中(旧值)
..并且这个 websocket 有很多不同的情况可能会导致更新更新。
redux 世界中是否有任何模式可以解决这个问题,或者 ngrx 世界中是否有人必须处理这个问题?我想到的唯一明智的事情是在你输入时将任何值保存到商店,这需要 Hook Angular react 形式来存储,这是一个巨大的痛苦,并且 ngrx/forms不会很快到来。但我敢肯定,一定有人已经想出了一些简单的解决方案。
谢谢!
(您可以阅读关于 gitter 的后续讨论)
最佳答案
考虑将表单状态与规范化实体分开存储。例如,您的状态可能包含诸如 articleEditForm
或类似内容的属性。基于从您的路由器状态订阅以获取文章的 ID,combineLatest
与商店的当前状态以分派(dispatch)带有文章负载的“EDIT_ARTICLE”类型的操作。然后,reducer 将使用文章状态有效负载为您的商店状态设置 articleEditForm
属性。原始规范化实体只会在成功提交表单后更新 - 可能使用 articleEditForm
中的值或提交表单的服务的响应。这种方法的优点是在 redux 存储中拥有表单状态,用于更复杂的显示和验证场景。这些值可以在每次击键、输入更改、表单提交或任何满足您的用例需求的情况下在 redux 中更新。
这对于 80% 的简单表单来说都太过分了——替代方法是直接从商店中的规范化实体填充表单(可能使用 .take(1) 或使用路由器状态和 combineLatest 与商店来管理并发问题) .然而,即使只使用普通形式,状态仍然与您商店中的规范化实体分开管理 - 这是 IMO 问题的准确模型。
关于 Angular + redux/ngrx : state update vs. 形式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43217078/