当将Object.assign()与其他操作结合使用时,Ngrx observable不会对状态存储更改做出反应

时间:2017-02-09 07:51:29

标签: javascript angular redux ngrx

我很难理解为什么第一个样本似乎工作正常,但第二个样本无法解雇观察者。

// Working reducer
return Object.assign({}, state, {
    expanded: Object.assign({}, state.expanded, { clients: !state.expanded.clients })
});

// Faulty reducer - Devtools indicates a change but the observables 
// seem to not respond and pass on the information down the line
newState = Object.assign({}, state);
newState.expanded.clients = !state.expanded.clients;


// Selectors
import {createSelector} from 'reselect';
export const SIDEBAR = (state: AppState) => state.sidebar;
export const SIDEBAR_UI = createSelector<AppState, SidebarUIState, SidebarState>(
    SIDEBAR,
    (state: SidebarState) => state.ui
);

// Sidebar service
public getSidebarUIExpandedObservable(): Observable<SidebarUIExpandedState> {
    debug('Get sidebar UI expanded observable');
    return this._store.select(SIDEBAR_UI_EXPANDED);
}

3 个答案:

答案 0 :(得分:1)

Reducers需要使用不可变对象的纯函数。 因此,您不能改变newState对象,但是您必须创建一个在创建时具有明确新状态的新对象。

您的第一个示例符合不变性原则,因为在将此对象分配给目标对象(第一个参数)之前,Object.assign将第三个参数中对象的匹配属性复制到第二个参数中的对象副本。因此,原始状态保持不受影响,并且在目标对象中获得新状态。 换句话说,object.assign在内存中没有更改原始对象状态,并且返回值提供了准备好(不需要进一步的突变)新状态对象。 有关Object.assign()的更多信息:https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

在第二种情况下,首先创建一个新对象(不变性仍然有效),随后,通过赋值布尔值来改变状态,因此不变性原则被破坏,而且reducers通常不接受这个。

答案 1 :(得分:1)

在reducer中使用以下内容:

newState = Object.assign({}, state);
newState.expanded.clients = !state.expanded.clients;

state.expanded的内容正在变异。

newState.expandedstate.expanded引用相同的对象,并且该对象的client属性正在变异。查看expanded的代码将看到对象引用未更改,并且将假定内容未更改,但您已通过切换其clients属性的值来对其进行了更改。

答案 2 :(得分:1)

而不是:

newState = Object.assign({}, state);
newState.expanded.clients = !state.expanded.clients;

return Object.assign(
  {},
  state,
  {
    expanded: Object.assign(
      {},
      state.expanded,
      {
        clients: !state.expanded.clients
      }
    )
  }
);

特技: 当你有Typescript&gt; = 2.1.4时,你就可以这样做

return {
  ...state,
  {
    expanded: {
      ...state.expanded,
      {
        clients: !state.expanded.clients
      }
    }
  }
};