我不是Javascript专家,所以我想知道是否有人有一种"优雅"的方法来组合多个减缩器来创建一个全局状态(比如Redux).在状态更新多个组件等时不影响性能的功能..

假设我有一家store .js

import React, { createContext, useReducer } from "react";
import Rootreducer from "./Rootreducer"

export const StoreContext = createContext();

const initialState = {
    ....
};

export const StoreProvider = props => {
  const [state, dispatch] = useReducer(Rootreducer, initialState);

  return (
    <StoreContext.Provider value={[state, dispatch]}>
      {props.children}
    <StoreContext.Provider>
  );
};

除根剂.js

import Reducer1 from "./Reducer1"
import Reducer2 from "./Reducer2"
import Reducer3 from "./Reducer3"
import Reducer4 from "./Reducer4"

const rootReducer = combineReducers({
Reducer1,
Reducer2,
Reducer3,
Reducer4
})

export default rootReducer;

推荐答案

Combine slice reducers (combineReducers)

最常见的方法是让每个减速器管理自己的状态属性("切片"):

const combineReducers = (slices) => (state, action) =>
  Object.keys(slices).reduce( // use for..in loop, if you prefer it
    (acc, prop) => ({
      ...acc,
      [prop]: slices[prop](acc[prop], action),
    }),
    state
  );
Example:
import a from "./Reducer1";
import b from "./Reducer2";

const initialState = { a: {}, b: {} }; // some state for props a, b
const rootReducer = combineReducers({ a, b });

const StoreProvider = ({ children }) => {
  const [state, dispatch] = useReducer(rootReducer, initialState);
  // Important(!): memoize array value. Else all context consumers update on *every* render
  const store = React.useMemo(() => [state, dispatch], [state]);
  return (
    <StoreContext.Provider value={store}> {children} </StoreContext.Provider>
  );
};

按顺序组合减速器

在任意形状的状态下应用多个减速器in sequence,类似于reduce-reducers:

const reduceReducers = (...reducers) => (state, action) =>
  reducers.reduce((acc, nextReducer) => nextReducer(acc, action), state);
Example:
const rootReducer2 = reduceReducers(a, b);
// rest like in first variant

Combine multiple useReducer Hooks

您还可以将来自多个useReducer的调度和/或状态组合在一起,例如:

const combineDispatch = (...dispatches) => (action) =>
  dispatches.forEach((dispatch) => dispatch(action));
Example:
const [s1, d1] = useReducer(a, {}); // some init state {} 
const [s2, d2] = useReducer(b, {}); // some init state {} 

// don't forget to memoize again
const combinedDispatch = React.useCallback(combineDispatch(d1, d2), [d1, d2]);
const combinedState = React.useMemo(() => ({ s1, s2, }), [s1, s2]);

// This example uses separate dispatch and state contexts for better render performance
<DispatchContext.Provider value={combinedDispatch}>
  <StateContext.Provider value={combinedState}> {children} </StateContext.Provider>
</DispatchContext.Provider>;

总之

以上是最常见的变体.对于这些 case ,也有类似于use-combined-reducers的库.最后,结合combineReducersreduceReducers查看以下示例:

const StoreContext = React.createContext();
const initialState = { a: 1, b: 1 };

// omit distinct action types for brevity
const plusOneReducer = (state, _action) => state + 1;
const timesTwoReducer = (state, _action) => state * 2;
const rootReducer = combineReducers({
  a: reduceReducers(plusOneReducer, plusOneReducer), // aNew = aOld + 1 + 1
  b: reduceReducers(timesTwoReducer, plusOneReducer) // bNew = bOld * 2 + 1
});

const StoreProvider = ({ children }) => {
  const [state, dispatch] = React.useReducer(rootReducer, initialState);
  const store = React.useMemo(() => [state, dispatch], [state]);
  return (
    <StoreContext.Provider value={store}> {children} </StoreContext.Provider>
  );
};

const Comp = () => {
  const [globalState, globalDispatch] = React.useContext(StoreContext);
  return (
    <div>
      <p>
        a: {globalState.a}, b: {globalState.b}
      </p>
      <button onClick={globalDispatch}>Click me</button>
    </div>
  );
};

const App = () => <StoreProvider> <Comp /> </StoreProvider>
ReactDOM.render(<App />, document.getElementById("root"));

//
// helpers
//

function combineReducers(slices) {
  return (state, action) =>
    Object.keys(slices).reduce(
      (acc, prop) => ({
        ...acc,
        [prop]: slices[prop](acc[prop], action)
      }),
      state
    )
}

function reduceReducers(...reducers){ 
  return (state, action) =>
    reducers.reduce((acc, nextReducer) => nextReducer(acc, action), state)
}
<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>

Reactjs相关问答推荐

两条react 路由的行为不同.有没有人能解释一下,我已经找了好几天了

Reaction Axios多部分/表单-数据数组不工作

react -在选项中 Select 我想要显示和图像.但当我 Select 该选项时,我希望控件仅显示该选项的文本部分

禁止直接访问Next.js中的页面,同时允许从应用程序内部访问

为什么我得不到我想要的数据?

透明MOV文件未出现在我的React网页中

使用experial_useFormState将参数传递给服务器操作

对于 ref 上的可见 prop 或 open 方法来react 组件,哪种方式更好?

使用D3.js绘制和展示弦图的右下方象限

将水平滚动视图添加到底部导航选项卡

如何在 React.js 中提取 PDF 的内容?

如何读取 null 的属性?

在 React 中使用复选框管理状态

顶点图表甜甜圈项目边框半径

在 Reactjs 中状态发生变化时渲染一个新组件而不替换旧组件

如何定制 React 热 toastr ?

如果查询不存在,如何返回所有产品?

为什么 state redux-toolkit 是代理?

RTK 查询 POST 方法不会改变数据

如何在按钮左下角制作 Material UI 菜单下拉菜单