Reputation: 10533
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.
Upvotes: 6
Views: 1429
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