可变 Redux 状态结构

Posted

技术标签:

【中文标题】可变 Redux 状态结构【英文标题】:Variable Redux State Structure 【发布时间】:2021-10-10 16:48:34 【问题描述】:

情况:

我有一个选项卡式react-redux 应用程序,我正在尝试找出我应该如何最好地构建状态(redux 存储/切片)。每个“选项卡”都有一个resourceRef,看起来类似于“app://new-tab”或“app://user/1234567890” - 选择选项卡时呈现的组件由其resourceRef 确定(例如,“app://new-tab”resourceRef 将呈现<NewTab> 组件,“app://user/1234567890”resourceRef 将呈现<UserDisplay> 组件等)。

目前我有tabsSlice 处理选项卡(添加、删除、更新选项卡状态等)。 tabSlice 的状态如下所示:

initialState: 
    tabs: [],
    activeTabUid: null


// Where tabs look like:
// 
//   title: (String),
//   resourceRef: (String - e.g. "app://new-tab"),
//   uid: (String - unique tab identifier),
//   componentState: (Object - serializable state object)
// 

// And updating a tab's componentState works like so:
reducers: 
    updateTabState: (state, action) => 
        const updateIndex, tabState = action.payload;
        state.tabs[updateIndex].componentState = tabState;
    

问题是我在tabsSlice 减速器的每个选项卡对象中都保留了componentState。我目前的解决方案是在父页面组件级别管理状态(例如<NewTab>) - 通过useSelector(selectTabState(tabUid)) 拉动选项卡状态,然后创建一堆状态更新函数以传递给子组件。这感觉不是很 Redux-y,我希望我的所有页面都由 Redux 切片管理 - 即为<NewTab><UserDisplay> 以及我所有其他可能的页面组件提供一个切片。问题是,我不知道如何实现这一点,因为这些页面状态是在另一个切片的数组中管理的。

问题:

如何构建此应用程序状态,以便我可以对所有内容使用切片(例如切片中的切片)?甚至可能吗?如果不可能,我目前的解决方案是否合理?

目前我对 Redux 应用程序状态结构的理解是新手,因此,我将不胜感激任何建议或有用资源的链接。


澄清说明:在此应用程序中预期具有相同页面类型的多个选项卡是完全合理的。例如,可能会打开许多​​ UserDisplay 选项卡 - 每个选项卡都有自己独立的状态,显示一个单独的用户。

【问题讨论】:

【参考方案1】:

我能够通过从父选项卡切片中删除页面状态并为系统中所需的每种页面类型创建缩减器切片来解决此架构挑战。每个页面切片都有该类型页面的集合,以及更新任何单个页面所需的操作。

做了以下考虑:

    单个页面状态(子状态)无法保留在选项卡状态(父状态)中 - 这样做是有道理的,因为每个页面状态始终与一个选项卡相关联。但是发现没有很好的方法来管理父切片内的复杂和可变的子组件状态。如果子页面不是可变的,那么从父页面中管理它就不会成为问题。

    在给定时间,标签中可能存在每个页面的多个实例。这意味着用于处理单个页面实例的简单切片将无法工作 - 页面切片必须设计为可容纳任意数量的此类页面。


这种性质的示例页面片段可能如下所示:

const initialPageState = ...;

export const slice = createSlice(
  name: <SliceName>,
  initialState:  instances:  , // Where a key/value entry looks like [uid]: state
  reducers: 
    addPage: (state, action) => 
      const uid = action.payload;
      state.instances[uid] = initialPageState;
    ,
    removePage: (state, action) => 
      const uid = action.payload;
      delete state.instances[uid];
    ,

    // Example instance-specific reducer
    setPageValue: (state, action) => 
      const uid, val = action.payload;
      state.instances[uid].val = val;
    
  
);

export const selectInstance = (uid) => (state) => state.<SliceName>.instances[uid];

所有对标签componentState 的引用都已被删除。这确实需要一些额外的工作,在tabSlice 选项卡和pageSlice 中的各个页面之间创建连接。此连接是通过标签uid 完成的。当然,在后台有一些代码可以在选项卡和页面之间进行协调 - 但希望这个答案总结了我遇到的问题类型的有效解决方案。

有时,如果嵌套化简器无法使用惯用且干净的 Redux 代码完成,则应改为在单独的切片中完成该化简,并且可以通过有效的状态/动作管理来管理任何必要的状态链接。

【讨论】:

以上是关于可变 Redux 状态结构的主要内容,如果未能解决你的问题,请参考以下文章

javascript 更新状态React Redux不可变

不可变状态更新。在 Redux 中更新对象数组

React Redux:在 Reduce 状态下使用不可变

我想以不可变的方式更新状态对象,以便react和redux正常工作?

如何更新 LocalStorage 中持久化的 Redux 状态结构

#yyds干货盘点#Redux 源码与函数式编程