Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing data between slice reducers when using createReducer

I have a ReactJS app in TypeScript with redux and I'm using redux-toolkit to build my reducers. As the app has grown larger, I want to start refactoring my reducers.

My redux state looks like the following:

{
  customers: Customers[],
  orders: {
    state1: SomeIndependentState1,
    state2: SomeIndependentState2,
    state3: SomeDependentState2,
    state4: SomeDependentState3,
  }
}

The customers and orders slices are independent and I can easily write two separate reducers for them, combining them with combineReducers later.

Now, I want to break down my orders reducer further.

  • state1 and state2 are completely independent.
  • state3 depends on data from state1.
  • state4 depends on data from state1 and state2.

Is there a way to continue using createReducer from redux-toolkit (or some other functionality from the toolkit) to create reducers for each nested slice within the orders slice?

As I've started rewriting my reducer for orders, here's what I have so far:

export const ordersReducer = (state: Orders, action: AnyAction) => {
  return {
    state1: state1Reducer(state?.state1, action),
    state2: state2Reducer(state?.state2, action),
    state3: {}, // not sure how to write a reducer for this slice and satisfy its dependency on state1
    state4: {}, // not sure how to write a reducer for this slice and staisfy its dependency on state1 and state2
  }
};

const initialState1: State1 = {};
export const state1Reducer = createReducer(initialState1, (builder) => 
  builder
    .addCase(...)
    .addCase(...)
);

const initialState2: State2 = {};
export const state2Reducer = createReducer(initialState2, (builder) => 
  builder
    .addCase(...)
    .addCase(...)
);

Note: I don't have control over the structure of my redux state. I'm not completely tied to using redux-toolkit but would need a good justification to have my team move away from it.

like image 954
K Mehta Avatar asked May 02 '20 18:05

K Mehta


People also ask

How do you share States between reducers?

How do I share state between two reducers? Do I have to use combineReducers ? ​ The suggested structure for a Redux store is to split the state object into multiple “slices” or “domains” by key, and provide a separate reducer function to manage each individual data slice.

Can we use multiple reducers?

You can use it at all levels of your reducer structure, not just to create the root reducer. It's very common to have multiple combined reducers in various places, which are composed together to create the root reducer.

How do you pass multiple reducers in Redux?

It turns out that Redux lets us combine multiple reducers into one that can be passed into createStore by using a helper function named combineReducers . The way we combine reducers is simple, we create one file per reducer in the reducers directory. We also create a file called index. js inside the reducers directory.


1 Answers

Just pass everything to the reducer that it needs. In this case, I would pass the whole orders state instead of passing state1, state2, state3, etc.

export const ordersReducer = (orders: Orders, action: AnyAction) => {
  return {
    // ...
    state3: state3Reducer(orders, action),
    // ...
  }
};

const initialState3: State3 = {};
export const state3Reducer = createReducer(initialState3, (builder) => 
  builder
    .addCase(someAction, (orders, action) => orders.state3 + orders.state1) // or anything else
    .addCase(...)
);

I renamed state to orders. I know that the canonical docs use state a lot, but that will get very confusing very quickly.

This is of course if state3 depends on the old state1. If it depends on the new value then you must have all the data that state3 needs in your action and the old state1. (Which leads back to the above solution). If you do not, your reducers are not pure functions.

Don't stress too much about your reducers. They have to be pure functions but they can have any number and type of args and return anything. They don't always have to strictly match the "relevant state prop to the relevant state prop".

like image 187
Bertalan Miklos Avatar answered Nov 10 '22 22:11

Bertalan Miklos