如何为这些要求有效构造一个还原状态?

时间:2018-12-05 02:21:05

标签: angular redux ngrx

我有一个复杂的Web应用程序状态,需要跟踪各种事物,包括当前选择的项目,要显示的项目ID等。Web应用程序也可以具有多个“状态”,一次只能激活1个。

例如,我有3个“选项卡”,具体取决于所选的选项卡将确定从哪个状态加载所有属性。因此,有效地,我具有相同状态的3个实例,并存储了不同的值。

该如何构造?目前,我已经将它作为一个数组来完成,但是当我改变一件事情的时候,由于角度重新渲染了状态对象中的所有内容,所以它似乎显然无效。

这是当前状态结构的一个示例:

GlobalState {
    tabStates: TabState[]
    selectedTabId: number
}

TabState {
    tabId: number
    selectedItem: string
    otherSelectedItems: string[]
}

我的标签状态包含更多内容,但我尝试简化它。

我应该将TabState内的每个属性都分解成自己的状态,例如,selectedItem属性看起来像这样吗?

SelectedItemState {
    selectedItems: { [tabId: number]: string };
}

任何建议将不胜感激,如果我的问题不够清楚,请回答,谢谢。

更新1

除非我扩展了整个featureState,否则我的选择器不会返回新值。我只想传播状态的单一属性,并让选择器认识到这一点,我在做什么错?

我处于以下状态

appState: {
    feature1State: {
        tabIds: number[],
        selectedTabId: number,
        items: Item[], // Yes I will change this to entity pattern
        selectedItemId: {[tabId: number]: id}
    }
}

还有我用于Feature1State的特征简化器:

UPDATE_SELECTED_ITEM: {
    feature1State.selectedItemId = { ...feature1State.selectedItemId };
    feature1State.selectedItemId[feature1State.selectedTabId] = action.payload.id;
    return feature1State;         
}

还有选择器

export const getFeature1State = createFeatureSelector<Feature1State> . 
('feature1State');

export const getSelectedIdForActiveTab = createSelector(
getFeature1State,
(state: Feature1State): number => 
state.selectedItemId[state.selectedTabId]);

1 个答案:

答案 0 :(得分:1)

绝对最好避免为您要修改的任何内容使用数组。 如果您需要保持顺序,则可以保留一组id字符串。 (话虽这么说,但在我从事的应用程序中,我们将项目数组保留为要显示的页面,但这些项目只是对对象中值的引用。)

state: {
  tabStates: {
    [tabId]: {
      tabId: number
      selectedItemId: string
      otherSelectedItems: {
        [itemId]: string
      }
    },
    selectedTabId: number
  },
}

更新1

**我对在Redux中使用Angular或React是否有所不同不熟悉

您的化简器应该是一个具有状态并返回新状态对象的函数,而不会改变化简器正在执行的现有状态。

对于我建议的状态形状(由于我难以理解您的复杂性),还原器来更新所选标签的所选项目将是

(tabStates, action) => {
  return {
    ...tabStates,
    [tabStates.selectedTabId]: {
      ...tabStates[tabStates.selectedTabId],
      selectedItemId: action.payload.id
    }
  }
}

(我修改了建议的状态,在tabStates中包含selectedTabId)

这可以通过使用浸入式(与上面相同)来简化。

import produce from "immer";

(tabStates, action) => {
  return produce(tabStates, draft => {
    draft[tabStates.selectedTabId].selectedItemId = action.payload.id
  });
}

该过程将创建一个新的状态对象,其中包含对原始状态的所有属性的引用,然后仅将需要更改的值替换为新的对象/值。

对于选择器,您只需要在选择器执行大量计算的地方或每次使用都会产生新对象的mapreduce或类似内容的地方使用reselect即可-render,即使对象中包含的值没有更改。

在这种情况下,您可以使用非常简单的选择器,因为您要直接从状态返回值。

(state: TabStates): number => state[state.selectedTabId].selectedItemId);