Ngrx - 选择器在存储更改后没有发出新值
Posted
技术标签:
【中文标题】Ngrx - 选择器在存储更改后没有发出新值【英文标题】:Ngrx - selector is not emitting new value after store change 【发布时间】:2019-01-21 12:42:30 【问题描述】:我的状态看起来像这样:
export interface State
modules: Module[];
Module 接口类似于:
export interface Module
name: string;
structure:
moduleID: string;
icon: string;
...
;
data: [id: string; value: string; ];
模块中的数据连接到输入字段和组合框。当用户更改输入字段中的某些内容时,将调度一个操作,并且reducer 使用给定数据对象的新数据值更新存储。我已经验证了更改发生在商店中。
Reducer 正在执行以下操作:( getModules() 只返回具有该名称的模块,而 changeElementData() 找到要更改的元素并对其执行 data.value = value)
case fromTitelActions.SET_DATA:
const stateCopy = ...state;
const moduleToChange = getModule(action.payload.nameOfModule, stateCopy.modules);
action.payload.data.forEach(data => changeElementData(moduleToChange, data.Id, data.value));
return stateCopy;
我正在尝试订阅特定的数据值并检测更改。我的选择器如下所示:
export const getDataElementValue = (moduleName, elementId) => createSelector(getModules,
modules =>
const module = modules.find(m => m.name === moduleName);
const data = module.data.find( d => d.id === elementId);
return data.value;
);
订阅选择器后,我会在其中获得当前值,但无论减速器更新该特定数据对象多少次,它都不会再次触发。有什么想法我想念的吗?谢谢。
【问题讨论】:
那个reducer不是一个纯函数——retrieveState()
是做什么的? reducer 必须是纯函数,这意味着对于给定的输入(即参数集),它必须始终执行相同的操作。 retrieveState 不接受任何参数,因此它返回的任何内容都必须依赖于传递给 reducer 的参数以外的其他内容。我不知道这是否是问题,但这是 /a/ 问题:)
那是我在编辑代码发布到这里时犯的一个错误。实际上它只是返回 stateCopy。状态也保存在本地存储中,但这对我的问题并不重要,所以我跳过了。感谢您指出我编辑了我的问题。
您也不应该将状态保存到减速器的本地存储中,因为这也会破坏它的纯函数方面。如果您想将状态保存在本地存储中,请选择状态,当 observable 发出时,将状态放入本地存储。
【参考方案1】:
问题可能是因为您的 changeElementData 函数在更新 moduleToChange 上的属性时没有创建新对象。
我猜你有这样的事情:
function changeElementData(moduleToChange, id, value)
moduleToChange.elements.forEach((el) =>
if (el.id == id) el.value = value;
);
你需要这样的东西:
case fromTitelActions.SET_DATA:
const stateCopy = ...state;
stateCopy.modules = stateCopy.modules.map((moduleToChange) =>
if (module.name != action.payload.nameOfModule) return moduleToChange;
else return action.payload.data.map(data => changeElementData(moduleToChange, data.Id, data.value));
);
return stateCopy;
function changeElementData(moduleToChange, id, value)
let found: boolean = false;
let newModule = module;
if (moduleToChange.elements.find((el) => el.id == id))
newModule =
...moduleToChange,
elements: moduleToChange.elements.map((el) =>
if (el.id == id) return ...el, value: value ;
else return el;
)
return newModule;
在状态上更新对象的属性时,您必须始终创建一个新的包含对象,因为 NGRX 使用简单的对象相等性来确定某些内容是否已更改并触发相关的 observables。如果您更新对象的属性,该对象本身仍具有与其先前版本相同的引用,因此 NGRX 将假定它未更改。
【讨论】:
以上是关于Ngrx - 选择器在存储更改后没有发出新值的主要内容,如果未能解决你的问题,请参考以下文章