按键修改嵌套对象不会触发 NGRX 中的效果
modifying nested object by key do not trigger effect in NGRX
我有一家 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;
};
此更改已正确应用到商店中
问题是,我的选择器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 件 =>
gridLayout: {
[Breakpoints.Small]: GridLayout;
[Breakpoints.Large]: GridLayout;
};
现在再也不会触发了。
我也试过
return {
...state
}
编辑:
我改成了这个
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
}
}
}
}
};
};
虽然有效,但是很糟糕,有没有更好的方法?
您最后的编辑有效,因为您return正在创建新状态,而不是改变现有状态。
这里有一些"prettier"解决return新状态的方法。
方案一:ActionReducerMap
另一种解决方案是使用 ActionReducerMap
将你的 reducer 分解为专注于特定的状态。
我看到您的顶级功能名为 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
};
执行以下步骤进一步分解状态缩减器。
像这样创建一个网格布局缩减器:
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:克隆状态
如果您真的不想 return 新状态,您可以通过使用 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;
};
这个 return 的新状态,因为您已经完全克隆了状态。但是,这种方法将使用更多资源,因为您克隆整个状态只是为了修改一些属性。
我有一家 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;
};
此更改已正确应用到商店中
问题是,我的选择器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 件 =>
gridLayout: {
[Breakpoints.Small]: GridLayout;
[Breakpoints.Large]: GridLayout;
};
现在再也不会触发了。
我也试过
return {
...state
}
编辑:
我改成了这个
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
}
}
}
}
};
};
虽然有效,但是很糟糕,有没有更好的方法?
您最后的编辑有效,因为您return正在创建新状态,而不是改变现有状态。
这里有一些"prettier"解决return新状态的方法。
方案一:ActionReducerMap
另一种解决方案是使用 ActionReducerMap
将你的 reducer 分解为专注于特定的状态。
我看到您的顶级功能名为 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
};
执行以下步骤进一步分解状态缩减器。
像这样创建一个网格布局缩减器:
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:克隆状态
如果您真的不想 return 新状态,您可以通过使用 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;
};
这个 return 的新状态,因为您已经完全克隆了状态。但是,这种方法将使用更多资源,因为您克隆整个状态只是为了修改一些属性。