在 Redux 中更新嵌套状态的更清洁/更短的方法?

新手上路,请多包涵

有时减速器会变得有点混乱:

 const initialState = {
    notificationBar: {
        open: false,
    },
};

export default function (state = initialState, action) {
  switch (action.type) {
    case actions.LAYOUT_NOTIFICATIONBAR_OPEN:
      return Object.assign({}, state, {
        // TODO: Find a cleaner way to do this!
        notificationBar: Object.assign({}, state.notificationBar, {
          open: true,
        }),
      });
    default:
      return state;
  }
}

有没有更简洁的方法来做到这一点?

原文由 ffxsam 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 305
2 个回答

UPD :它现在是 ES2018 的一部分

它可能会通过 非标准化 但属性传播的语法 略有改进:

 return {
    ...state,
    notificationBar: {
        ...state.notificationBar,
        open: true,
    },
};

原文由 zerkms 发布,翻译遵循 CC BY-SA 4.0 许可协议

尽管可以使用扩展运算符,但还有许多其他方法可以实现相同的结果,甚至不需要未来的 JS 编译器来实现非标准化功能。以下是一些其他选项,排名不分先后。

返回文字

如果您确定您的状态不会增长,那么您可以简单地以文字形式返回整个新状态。

 return {
  notificationBar: {
    open: true
  }
}

但是,这通常并不合适,因为您的状态不太可能如此简单。


组合减速器

Redux 为您提供了一种实用方法,用于组合多个在状态对象的不同部分上工作的缩减器。在这种情况下,您将创建一个 notificationBar reducer 来单独处理该对象。

  createStore(combineReducers({
   notificationBar: function(state=initialNBarState, action) {
     switch (action.type) {
       case actions.LAYOUT_NOTIFICATIONBAR_OPEN:
         return Object.assign({}, state, { open: true });
   }
 });

这使您不必担心顶级属性,从而避免嵌套调用 Object.assign

如果您的状态可以在逻辑上分解为明确定义的部分,那么这可能是解决此问题的最惯用的方法。


使用不可变数据

您可以使用持久数据结构库来创建可以修改以返回副本的数据结构。

Mori是将Clojure的数据结构和函数式API编译成JS的结果。

 import { hashMap, updateIn } from 'mori';

const initialState = hashMap(
  "notificationBar", hashMap(
    "open", false
  )
);

// ...

return updateIn(state, ['notificationBar', 'open'], true);

不可变JS

ImmutableJS 是一种更具命令性的方法,可将哈希数组映射尝试的语义从 Clojure 的持久数据结构引入 Javascript。

 import { Map } from 'immutable';

const initialState = Map({
  notificationBar: Map({
    open: true
  });
});

// ...

return state.setIn(['notificationBar', 'open'], true);


别名 Object.assign

您可以创建一个更友好的版本 Object.assign 来编写上面代码的更简洁版本。事实上,它几乎可以像 ... 运算符一样简洁。

 function $set(...objects) {
  return Object.assign({}, ...objects);
}

return $set(state, {
  notificationBar: $set(state.notificationBar, {
    open: true,
  })
});


使用不可变助手

有许多库也提供不变性帮助程序来修改常规可变对象。

反应插件更新

很长一段时间以来,React 都有一组内置的不变性助手。它们使用与 MongoDB 查询类似的语法。

 import update from 'react-addons-update';

return update(state, {
  notificationBar: {
    open: { $set: true }
  }
});

点属性不可变

该库允许您使用熟悉的点路径来指定对(嵌套)属性的更新。

 import dotProp from 'dot-prop-immutable';

return dotProp.set(state, 'notificationBar.open', true);

更新

该库是 react-addons-update 的包装器,并为更新(嵌套)属性提供了更实用的语法。

不是传递一个新值,而是传递一个接受旧值并返回新值的函数。

 import updateIn from 'update-in';

return updateIn(state, ['notificationBar', 'open'], () => true);

不可变路径

对于更新属性,这个库就像是 dot-prop-immutableupdate-in 之间的交叉。

 import path from 'immutable-path';

return path.map(state, 'notificationBar.open', () => true);

原文由 Dan Prince 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题