通过键修改嵌套对象不会在NGRX中触发效果。

问题描述 投票:1回答:1

我有一个NGRX商店看起来像这样。

export interface INavigationSettings {
  gridLayout: {
    [Breakpoints.Small]: GridLayout;
    [Breakpoints.Large]: GridLayout;
  };
  //...
}

我有一个动作,将应用修改这些GridLayout

const SET_NAVIGATION_GRID_VISIBILITY = (state: State, action: featureAction.SetNavigationGridVisibility) => {
  state.navigation.gridLayout[action.payload.size].visibility = {
    ...state.navigation.gridLayout[action.payload.size].visibility,
    ...action.payload.visibility
  };
  return state;
};

这个变化正确地应用在商店里 enter image description here

问题是,我的选择器 selectNavigationGridLayout

export const selectSettingsState: MemoizedSelector<object, State> = createFeatureSelector<State>('settings');

export const gridLayout = (state: State): {
    Small: featureModels.GridLayout;
    Large: featureModels.GridLayout;
} => state.navigation.gridLayout;

export const selectNavigationGridLayout: MemoizedSelector<object, {
    Small: featureModels.GridLayout;
    Large: featureModels.GridLayout;
}> = createSelector(selectSettingsState, gridLayout);

从不捕捉任何变化,也不调用变化状态槽的应用程序.这是很好的工作之前,当我有一个单一的对象gridLayout,但因为我是做移动,我分开在2件=&gt。

  gridLayout: {
    [Breakpoints.Small]: GridLayout;
    [Breakpoints.Large]: GridLayout;
  };

现在它从来没有触发。

我也尝试过

return {
   ...state
}

EDIT :

我改成了这个

const SET_NAVIGATION_GRID_VISIBILITY = (state: State, action: featureAction.SetNavigationGridVisibility) => {
  return {
    ...state,
    navigation: {
      ...state.navigation,
      gridLayout: {
        ...state.navigation.gridLayout,
        [action.payload.size]: {
          ...state.navigation.gridLayout[action.payload.size],
          visibility: {
            ...state.navigation.gridLayout[action.payload.size].visibility,
            ...action.payload.visibility
          }
        }
      }
    }
  };
};

它的工作,但它是可怕的,是不是有一个更好的方法?

angular redux ngrx ngrx-store
1个回答
1
投票

你最后的编辑工作是因为你返回的是新状态,而不是突变现有状态。

这里有一些 "更漂亮 "的解决方案来返回新状态。

解决方案1:ActionReducerMap

另一种解决方案是使用 ActionReducerMap 来分解你的减速器,使其专注于某一块状态。

我看到你的顶层功能名为 settings. 所以你的商店看起来有点像这样。

interface StoreState {
  settings: SettingsFeatureState;
}

interface SettingsFeatureState {
  navigation: INavigationSettings;
}

interface INavigationSettings {
  gridLayout: GridLayoutState;
}

interface GridLayoutState {
  [Breakpoints.Small]: GridLayout;
  [Breakpoints.Large]: GridLayout;
}

而你的设置还原器看起来就像这两个中的一个:

function settingsReducer(state: SettingsFeatureState, action: Action): SettingsFeatureState {
 // ...
}

// or

function navigationReducer(state: INavigationSettings, action: Action): INavigationSettings {
 // ...
}

const settingsReducer: ActionReducerMap<SettingsFeatureState> = {
  navigation: navigationReducer
};

做以下步骤来分解你的状态还原器,甚至更多。

创建一个网格布局reducer,像这样。

function gridLayoutReducer(state: GridLayoutState, action: Action): GridLayoutState {
  // ...
}

const SET_NAVIGATION_GRID_VISIBILITY = (state: GridLayoutState, action: featureAction.SetNavigationGridVisibility): GridLayoutState => {
  return {
    ...state,
    [action.payload.size]: {
      ...state[action.payload.size],
      visibility: {
        ...state[action.payload.size].visibility,
        ...action.payload.visibility
      }
    }
  };
};

然后,修改你的navigationReducer,将其注册为 gridLayoutReducer 如下图所示。

const navigationReducerMap: ActionReducerMap<INavigationSettings> = {
  gridLayout: gridLayoutReducer
}

// This function has the following signature:
// navigationReducer(state: INavigationSettings, action: Action): INavigationSettings 
const navigationReducer = combineReducers(navigationReducerMap)

解决方案2:克隆国

如果你真的不想返回新的状态,你可以保留原来的逻辑,但稍作修改,使用类似于 lodash 来深度克隆状态。

const SET_NAVIGATION_GRID_VISIBILITY = (state: State, action: featureAction.SetNavigationGridVisibility) => {
  const newState = _.deepClone(state)

  newState.navigation.gridLayout[action.payload.size].visibility = {
    ...newState.navigation.gridLayout[action.payload.size].visibility,
    ...action.payload.visibility
  };
  return newState;
};

这将返回新的状态,因为你已经完全克隆了状态。但是,这种方法会使用更多的资源,因为你克隆整个状态只是为了修改几个属性。

© www.soinside.com 2019 - 2024. All rights reserved.