I just learned Redux , and i am here to share what are the things that made me understand what's going on ...
let's start with why to use Redux:
There is interesting discussion in stackoverflow that explains why and when do we need Redux.
In addition to that :
let's say an app with 50 components with their own states that communicate with each other and update each other's state .
Now , in the first tree , States of the app become so convoluted and confusing , whereas in second tree , it's pretty clean because of the master state . Components send requests to update master state and stage changes of master state flow down to component .
Installation:
Consideration: you are already inside react project and have yarn installed .You can also use npm but i prefer yarn .
yarn add redux react-redux
Store , Reducer , Action
STORE:
Store is basically where entire state of the app lives . This is just one big object.Only way to change the state is to dispatch an action for it .Action:
Action is just an object with type and payload that is sent or dispatched from view which are sent to Reducer .-
Reducer:
Reducer is a pure function that reads the state and action.It handles how to update the state based on the action props and returns the next state .
Create Store :
Import createStore from redux in your index.js file .
import { createStore } from 'redux';
Remember that there is only one store in an Application .
Now create a store .
const store = createStore(
reducer,
{
products: [{ name: "iphone" }],
user: ["michael"]
},
allenhancer
);
createStore() function takes three arguments,first of which is reducer function , second is initial or pre-loaded state and last is store enhancer.
we will talk about store enhancer next time , for now let's write this
const allenhancer = window.devToolsExtension && window.devToolsExtension();
This is for Redux devtools . You can add it on your browser extension. For chrome , you can add it from here .
Create and dispatch an action :
Action is just an object with type and payload , let's create it :
const action = {
type:'changestate' ,
payload:{
newState:'New state'
}
};
Now dispatch an action object with store object that we just created above :
store.dispatch(action);
Define a reducer function and handle the action props:
function reducer(state , action){
if(action.type=== 'changeState'){
return action.payload.newState;
}
return 'default-value';
}
Reducer function takes two arguments , state and action which is dispatched by store and return next state .
you can console the store state with
console.log(store.getState());
where we can see that state has been changed to 'New State' . store.getState() returns the current state tree of your application . It is equal to last value returned by store's reducer.
Dividing state with multiple Reducer :
Putting all your updates or handling logic in single reducer function can become unmanageable . So , what we do is split the logic into multiple functions and call those functions from parent function .
All functions have (state , action)
as parameter .
You may be thinking " how to call different reducer if we have multiple one ?" . Well,here comes the rescuer : combineReducers()
.
For that , import it from redux . The import line from above looks this :
javascriptimport { combineReducers, createStore } from 'redux'
Refactoring of Reducer function :
This is our reducer function that add user or product into our state , and return new state with payload added to product or user as per 'type' :
function reducer(state = "", action) {
switch (action.type) {
case "UPDATE_USER":
let temp_state_user = Object.assign({}, state);
temp_state_user.user.push(action.payload);
return temp_state_user;
case "UPDATE_PRODUCT":
let temp_state_product = Object.assign({}, state);
temp_state_product.product.push(action.payload);
return temp_state_product;
default:
return state;
}
}
Reducer function handles the action on calling dispatch as :
store.dispatch({ type: "UPDATE_USER", payload: "PRAVIN" });
console.log(store.getState());
console.log() gives console output as :
Reducer function above takes switch operation to handle user and products update inside same function .This may be clumsy if this grows . We now want to take slice of this render logic ,and put it inside individual function . combineReducers()
provide us this functionality to combine different reducing logic and make parent render function which can be made called by store on dispatch .
Let's refactor above render function
const initialState = null;
function user_reducer(state = initialState, action) {
switch (action.type) {
case "UPDATE_USER":
let users = state;
users.push(action.payload.user);
return users;
default:
return state;
}
}
function product_reducer(state = initialState, action) {
switch (action.type) {
case "UPDATE_PRODUCT":
let temp_state_product = Object.assign({}, state);
temp_state_product.push(action.payload);
return temp_state_product;
default:
return state;
}
}
combineReducer() combines both reducers and return parent reducer that can be attached with store.
const allReducers = combineReducers({
products: product_reducer,
user: user_reducer
});
and now we have store creation code as :
const store = createStore(
allReducers,
{
products: [{ name: "iphone" }],
user: ["michael"]
},
allenhancer
);
This also gives the same result in console after console.log(store.getState())
That's it for now ,
This is not good way to write all code inside index.js so next time we will start with directory/file hierarchy and about passing this state to view or component .
Top comments (3)
Thank you for the post, Pravin.
Would you be be able to update the post with a syntax highlight as to improve the readability? Refer to the Editor Guide for more info.
Thanks Sung for comment .
I did code highlighting ... Thanks again for comment and going through
this post .
Thank you, Pravin 😀