将 Redux Toolkit 的 createEntityAdapter 用于动态数据网格

Using Redux Toolkit's createEntityAdapter for dynamic data grids

我对使用 createEntityAdapter from Redux Toolkit 有疑问。

我有一个使用 AG Grid library's master/detail 功能显示包和包详细信息的应用程序。该应用程序首先加载包裹数据,然后在展开每个包裹行时获取详细数据。

我想使用 createEntityAdapter 以规范化的方式管理数据,但我无法弄清楚如何处理细节网格的动态特性。现在我有一个 reducer 切片,每次加载一组详细记录时都会创建一个新的 属性。 属性 键是父包行的 id,所以我的 data 切片在包数据和 123 详细数据加载后最终看起来像这样:

{
  PACKAGES: [{ id: 123, ...otherData }, { id: 124, ...otherData }],
  '123': [{ id: 456, ...otherDetailData }],
}

当用户展开 124 包行时,将获取该包的详细数据,然后如下所示:

{
  PACKAGES: [{ id: 123, ...otherData }, { id: 124, ...otherData }],
  '123': [{ id: 456, ...otherDetailData }],
  '124': [{ id: 457, ...otherDetailData }],
}

因此,虽然我可以将 PACKAGES 数据分解到它自己的实体适配器中,但我不能对细节网格做同样的事情,因为我无法提前了解它们中的每一个。

我想我和 this issue 的人有类似的问题。

我考虑过将所有详细数据存储在单个实体适配器中并由父级维护另一个索引 id,但这似乎很难保持同步。

有什么想法吗?这种情况下的最佳做法是什么?

我创建并维护了 Redux 工具包,实际上我最近确实用嵌套实体适配器做了一些类似的事情。

就我而言,我需要在添加或删除父项时维护这些辅助数据集。

interface ChildrenEntry {
  parentId: ParentId;
  children: EntityState<ChildType>
}

interface ChildrenData {
  parentId: ParentId;
  children: ChildType[];
}

interface NewChildAdded {
  parentId: ParentId;
  child: ChildType;
}

export const childEntriesAdapter = createEntityAdapter<ChildrenEntry>();
export const childrenAdapter = createEntityAdapter<ChildType>();

const initialState = childEntriesAdapter.getInitialState();

const createNewChildEntry = (parentId: ParentId) => ({
  parentId,
  children: childrenAdapter.getInitialState()
});

const childEntriesSlice = createSlice({
  name: "children",
  initialState,
  reducers: {
    childEntriesLoaded(state, action: PayloadAction<ChildrenData>) {
      const {parentId, children} = action.payload;
      const childEntry = state.entities[parentId];
      if (childEntry) {
        childrenAdapter.setAll(childEntry.children, children);
      }
    },
    // etc
  },
  extraReducers: builder => {
    builder
      .addCase(parentLoaded, (state, action) => {
        const childEntries = action.payload.map(parent => createNewChildEntry(parent.id));
        childEntriesAdapter.setAll(state, childEntries);
      })
      .addCase(parentDeleted, (state, action) => {
        childEntriesAdapter.removeOne(state, action);
      })
      .addCase(parentAdded, (state, action) => {
        const childEntry = createNewChildEntry(action.payload.id);
        childEntriesAdapter.addOne(state, childEntry);
      });
  }
})

可能有更好的方法来处理这个问题,但它足以满足我的需要。