web-dev-qa-db-fra.com

React useReducer: Comment combiner plusieurs réducteurs?

Je ne suis pas un expert Javascript donc je me suis demandé si quelqu'un avait une façon "élégante" de combiner plusieurs réducteurs pour créer un état global (comme Redux). Une fonction qui n'affecte pas les performances lors d'un état mettant à jour plusieurs composants etc.

Disons que j'ai un 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>
  );
};

Rootreducer.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;
4
Freddy.

Si vous souhaitez simplement obtenir une fonction de réduction de combinaison sans aucune bibliothèque tierce, procédez comme ci-dessous. (REF: source/code Redux) Le code de travail est ici https://codepen.io/rajeshpillai/pen/jOPWYzL?editors=001

J'ai créé deux réducteurs, un dateReducer et un autre counterReducer. Je l'utilise comme

const [état, répartition] = useReducer (combineReducers ({counter: counterReducer, date: dateReducer}), initialState);

Le code combineReducers

function combineReducers(reducers) {  
  return (state = {}, action) => {
    const newState = {};
    for (let key in reducers) {
      newState[key] = reducers[key](state[key], action);
    }
    return newState;
  }
}

Utilisation: extraire l'état respectif

const { counter, date } = state;

REMARQUE: vous pouvez ajouter plus de fonctionnalités de type redux si vous le souhaitez.

Le code de travail complet (dans le cas où codepen est en panne :))

const {useReducer, useEffect} = React;


function dateReducer(state, action) {
  switch(action.type) {
    case "set_date":
      return action.payload;
      break;
    default:
      return state;
  }  
}

function counterReducer(state, action) {
  console.log('cr:', state);
  switch (action.type) {
    case 'increment': {
      return state + 1;
    }
    case 'decrement': {
      return state - 1;
    }

    default:
      return state;
  }
}

function combineReducers(reducers) {  
  return (state = {}, action) => {
    const newState = {};
    for (let key in reducers) {
      newState[key] = reducers[key](state[key], action);
    }
    return newState;
  }
}

const initialState = {
  counter: 0,
  date: new Date
};

function App() {
  const [state, dispatch] = useReducer(combineReducers({
    counter: counterReducer,
    date: dateReducer 
  }), initialState);  

  console.log("state", state);
  const { counter, date } = state;

  return (
    <div className="app">
      <h3>Counter Reducer</h3>
      <div className="counter">
        <button onClick={() => 
          dispatch({ type: 'increment'})}>+          
        </button>

        <h2>{counter.toString()}</h2>
        <button onClick={() => 
             dispatch({ type: 'decrement'})}>-
        </button>
      </div>
      <hr/>
      <h3>Date Reducer</h3>
      {date.toString()}
      <button className="submit" 
          type="submit"
          onClick={() => 
             dispatch({ type: 'set_date', payload:new Date })}>
           Set Date
        </button>
    </div>
  );
}

const rootElement = document.querySelector("#root");
ReactDOM.render(<App />, rootElement);  

REMARQUE: il s'agit d'un hack rapide (à des fins d'apprentissage et de démonstration uniquement)

0
rajesh pillai