
Reducers are the pure function that takes input as state & action and returns the new state. More clearly reducer dispatch the action to store which in turn changes the state of the store based on the type of action.
Now let’s create a reducer as a pure function with 2 parameters i.e state & an action. The job of this reducer is to return a new state based on the action. We are using an example of a store, the store that has multiple items & each item is having its id, description & availability.
int myId = 0;
function reducer(state ,action){
if(action.type === 'itemAdded')
return [
...state,
{
id:++myId,
describtion:action.payload.describtion,
availablity:false
}
];
else if(action.type === "itemRemoved")
return state.filter(item=>item.id!== action.payload.id);
else
return state; //if the action type doesnt match then we dont want to blow up or code hence we return the current state.
}
…state – it’s a spread operator to copy the state of the store, the alternative for this is we have immutability library or immer library.
What’s the problem with the above code?
The problem is the initial state, How? Let me explain.
initially, the state is undefined, redux call the reducer, and pass undefined as the value of the state. In this case, we want to return the initial state, but it returns the undefined.
How to return this initial state?
well, we can set the initial state using the concept of default argument. We can do it in two methods.
method 1:
function reducer(state=[],action){
//
}
method 2:
const initialState = {
value: 0
}
function reducer(state=initialState,action){
//
}
How to optimize above code more presiously?
Previously, we have used the if-else statement to decide action types. instead, we can use the switch & case statement as below.
const initialState = {
}
int myId = 0;
function reducer(state = initialState ,action){
switch(action.type){
case "itemAdded":
return [
...state,
{
id:++myId,
describtion:action.payload.describtion,
availablity:false
}
];
break;
case "itemRemoved":
return state.filter(item=>item.id!== action.payload.id);
break;
default:
return state;
}
Combining Multiple reducers into One Main Reducer(using custom & pre-defined function) :
Up to now, we have created a reducer to handle a single type of state or data say items. but with complex applications, we have multiple slices of states in the redux store say user state & items state.
For both users & items, we need to create separate reducers to maintain the code & increase the readability of the code.
We can combine these 2 reducers either by using our own custom reducer or by using redux pre-defined functions.
Let’s see how can we combine multiple reducers
const initialState = {
users:[],
items:[]
}
int ItemId = 0;
function itemReducer(state = initialState.items ,action){
switch(action.type){
case "itemAdded":
return [
...state,
{
id:++ItemId,
describtion:action.payload.describtion,
availablity:false
}
];
break;
case "itemRemoved":
return state.filter(item=>item.id!== action.payload.id);
break;
default:
return state;
}
}
int userId=0;
function UserReducer(state = initialState.users ,action){
switch(action.type){
case "userAdded":
return [
...state,
{
id:++userId,
name:action.payload.name
}
];
break;
case "userRemoved":
return state.filter(user=>user.id!== action.payload.id);
break;
default:
return state;
}
Here itemReducer & UserReducer are 2 reducer functions which namely handles events for updating/modifying items & users in the redux store.
Now let’s combine them.
1.Custom Function:
function Appreducer(state=initialState,action){
Return {
Items:itemReducer(state.Items,action),
Users:Userreducer(state.Users,action)
}}
2.combineReducers Function:(Redux built-in function)
Const AppReducer = combineReducers({
Items:itemReducer,
Users:Userreducer
})
We can pass this AppReducer to the redux store & then now we are ready to use multiple reducers in our application.