繁体   English   中英

Redux:重用Reducer更新多个状态属性

[英]Redux: Reuse a reducer to update multiple state properties

也许这只是我的Redux知识中缺少的一条信息,但是即使经过数小时的搜索,我仍然不知道如何创建可重用的reducer来更新许多状态属性。

假设,我创建了一个简单的组件MySwitch提供了一个用于编辑布尔值的UI。 有一个相关的动作和一个reducer来更新状态。 我了解如何使其适用于该州的特定物业。 但是,如何创建组件(和相关的reducer)以与商店中的任何布尔值一起使用,而又不为它们中的每一个创建特殊的reducer?

假设状态看起来像这样:

{
  items: {
    house: { isBig:true, location: ... },
    car: { isMine:true, isBroken:false, ... }
  },
  books: [
    { id:1, available:true, title:... },
    { id:2, available:false, title:... }, ...
  ]
}

正确的机制来创建的各种实例什么MySwitch查看和编辑任何给定值-像items.house.isBigitems.car.isMinebooks[1].available -和相同的减速更新吗?

我可以使用connect将属性注入到组件中,例如:

ASwitch = connect(state => ({
  valueToEdit: state.items.car.isMine
})(MySwitch)

但是我不知道如何将其传递给reducer以及如何让它更新状态的相应部分。 我以为可以提供该操作的路径(即"items.car.isMine" ):

export const editBoolean = ( path, value ) => {
  return {
    type: 'BOOL_EDIT',
    payload: { path, value }
  }
}

然后在reducer中使用类似这样的东西:

case 'BOOL_EDIT': {
  const { path, value } = action.payload;
  return {
    ...state,
    [path]: value
  }
}

但它不起作用,似乎ES6不支持可变的计算属性,而是创建了诸如state["items.car.isMine"]类的属性。

我不知道该怎么继续。 谢谢你的帮助。

我认为您的想法正确,但您的问题并非完全针对redux,您只需使用希望通过路径定位的更新节点克隆状态即可。

你可以用这样的东西

const singlePathReducer = (state, { payload: { path, value } }) => path.reduce(({ nextState, branch = nextState }), node) => {
  if (node !== path[path.length - 1]) {
    // this was the part you were missing; you need to walk down your state tree
    // by passing a reference of the current branch to the next reduce callback
    return { nextState, branch: nextState[node] };
  }

  // mutate your nextState, this is ok
  branch[node] = value;
  return nextState;

  // don't mutate state, create a copy
}, { nextState: { ...state } });

如果我没弄错js中的按引用传递是如何工作的,这应该可以工作。 完整的实现将是这样的(将singlePathReducer fn分开保存可以使单元测试更加容易):

const rootReducer = (state, action) => {
  switch action.type {
    case 'BOOL_EDIT':
      return singlePathReducer(state, action);
    default:
      return state;
  }
};

*免责声明:对我来说,这有点像是Redux的反模式,因为它允许通过一次操作将存储中的任何值设置为任何值。 明智地使用它。

````
const set = require("lodash/set");
const { produce } = require("immer");

case 'BOOL_EDIT': {
  const { path, value } = action.payload;
  return produce(state, draft => {
    set(draft, path, value);
  });
}
```

editBoolean("items.car.isMine", false)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM