K Mehta
K Mehta

Reputation: 10533

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.

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.

Upvotes: 6

Views: 1429

Answers (1)

Bertalan Miklos
Bertalan Miklos

Reputation: 231

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".

Upvotes: 1

Related Questions