小编典典

挂钩:使用useReducer时结合多个减速器?

reactjs

我想使用嵌套化简器,而不是在作为第一个参数传递给的主化简器中使用嵌套的switch语句(甚至可以这样做?)useReducer。这是因为我的减速器功能取决于多个switch(第一个操作,然后是水果类型)。

我查找了“嵌套的简化器”,但是这些问题的解决方案似乎都与redux和combineReducers挂钩,而Hooks却没有。

演示代码(即使codesandbox再次关闭):

它实际上并没有显示在codesandbox中(因为沙箱本身无法正常工作),但是在我自己的计算机上Uncaught TypeError: fruits.apples.map is not a function,单击Add按钮后得到了。但是,在此之前,map可以正常工作,并且所有项目均按预期方式呈现。


阅读 329

收藏
2020-07-22

共1个答案

小编典典

您的代码中有一些错误,例如缺少class而不是属性。我修改了您的示例,在这里看看。className``key

简化器是纯函数,也很重要-
当通过适当的操作触发更改时,始终返回新状态,而不会使先前的状态(和嵌套属性)发生变化。如果没有reducer无法处理该操作,则只需返回先前的状态-
不要抛出reducer,这也将使其变得不纯。

形状的替代方法是让每个子级减速器负责整个状态树的某些子状态,以使其更具可伸缩性和可组合性(Link)。因此,一种还原剂可用于苹果,一种还原剂可用于香蕉和一种橙子(第一种水果类型,然后操作)。但原则上,您可以根据需要/形状来处理形状。

希望能帮上忙。


更新:

如果您寻求combineReducersfor
的类似Redux的实现useReducer,也可以看看Lauri的答案,尽管我建议在大多数情况下使用不同的实现。在以下示例中,每个化简器仅获得其状态的自己的部分(“切片”),这降低了其复杂性。您还可以很好地扩展此解决方案-只需添加一个新的属性+ reducer:

// combine reducers ala Redux: each can handle its own slice
const combineReducers = slices => (prevState, action) =>
  // I like to use array.reduce, you can also just write a for..in loop 
  Object.keys(slices).reduce(
    (nextState, nextProp) => ({
      ...nextState,
      [nextProp]: slices[nextProp](prevState[nextProp], action)
    }),
    prevState
  );

// atomar reducers only get either apple or orange state
const apples = (state, action) => action.type === "ADD_APPLE" ? state + 1 : state;
const oranges = (state, action) => action.type === "ADD_ORANGE" ? state + 1 : state;

const App = () => {
  const [state, dispatch] = React.useReducer(
    combineReducers({ apples, oranges }), // here we create the reducer slices
    { apples: 0, oranges: 0 }
  );
  const handleAddApple = () => dispatch({ type: "ADD_APPLE" });
  const handleAddOrange = () => dispatch({ type: "ADD_ORANGE" });

  return (
    <div>
      <p>Apples: {state.apples}, Oranges: {state.oranges}</p>
      <button onClick={handleAddApple}>add Apple</button>
      <button onClick={handleAddOrange}>add Orange</button>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));


<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
2020-07-22