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 - 选择器在存储更改后没有发出新值的主要内容,如果未能解决你的问题,请参考以下文章

jQuery类选择器在类更改后不选择

在单元测试中使用参数模拟 ngrx 存储选择器(Angular)

选择器在数据更改时删除选定的段

Django - 如何使日期选择器在更改时提交表单

角材料步进器在选择更改之前并防止在某些条件下进行步进更改

ngrx 4 选择器返回整个状态而不是子状态