如何在Redux中分离UI和应用程序状态

时间:2015-11-05 22:46:17

标签: reactjs redux

编写react-redux应用程序时,我需要在全局状态树中保留应用程序和UI状态。设计它的最佳方法是什么?

假设我有一个待办事项列表:

{
  items: [
    { id: 1, text: 'Chew bubblegum' },
    { id: 2, text: 'Kick ass' }
  ]
}

现在我想让用户选择并展开项目。如何建模状态形状(至少)有两种选择:

{
  items: [
    { id: 1, text: 'Chew bubblegum', selected: true, expanded: false },
    { id: 2, text: 'Kick ass', selected: false, expanded: false }
  ]
}

但这是将UI状态(selectedexpanded)与应用程序状态混合在一起。当我将待办事项列表保存到服务器时,我想只保存应用程序状态,而不是UI状态(在真实应用程序中,UI状态可以包含模态对话框的状态,错误消息,验证状态等)。

另一种方法是为项目的UI状态保留另一个数组:

{
  items: [
    { id: 1, text: 'Chew bubblegum' },
    { id: 2, text: 'Kick ass' }
  ],
  itemsState: [
    { selected: true, expanded: false },
    { selected: false, expanded: false }
  ]
}

然后在渲染项目时必须将这两种状态组合在一起。我可以想象你可以在zip函数中connect这两个数组来简化渲染:

const TodoItem = ([item, itemState]) => ...;
const TodoList = items => items.map(item => (<TodoItem item={item} />));

export default connect(state => _.zip(state.items, state.itemsState))(TodoList);

但状态更新可能很痛苦,因为itemsitemsState必须保持同步:

  1. 删除项目时,必须删除相应的itemState。
  2. 重新排序项目时,itemsState也必须重新排序。
  3. 当从服务器更新待办事项列表时,必须将ID保持在UI状态并进行一些对帐。
  4. 还有其他选择吗?或者是否有任何库可以帮助保持应用状态和UI状态同步?

2 个答案:

答案 0 :(得分:12)

normalizr启发的另一种方法:

{
    ids: [12,11], // registry and ordering
    data: {
        11: {text: 'Chew bubblegum'},
        12: {text: 'Kick ass'}
    },
    ui: {
        11: { selected: true, expanded: false },
        12: { selected: false, expanded: false }
    }
}

答案 1 :(得分:0)

我目前正在考虑这个侧面项目。我将接近它类似于上面的Rick方法。数据{}作为事实的来源,您可以使用它来推动本地ui变化(反映最新状态)。你需要在渲染之前将数据和ui合并在一起,我自己也在几个地方尝试过。我会说,就保持同步而言,它不应该太糟糕。基本上,无论何时保存/获取数据,您都要更新数据{}并清除ui {}以准备下一个用例。