# Redux and Redux-toolkit 101.
For the data in the A component to be accessed in the C component, it has to be passed down as prop to the B component, and then finally the C component. This is known as threading.
Prop drilling does have its downsides, and in some cases it isn’t worth it. As your codebase increases, prop drilling can make your code overly complicated, and this can only get worse with more additions.
In addition to this, props can be passed down to components that don’t necessarily need it just for the data to get to the child component, leading to an unnecessary increase in the codebase.
So, to solve this ,we uses the State management libraries like ReduxJS/Redux-Toolkit or ContextAPI.
Below is the Basic Visual takeaways to understand the terms in Redux.
In Redux , we have 1) Actions 2) Store 3) Type 4)Payload 5) Reducer 6) Dispatch
In the above example :
-
Action : We are depositing 100rs to the Bank(Store).. what you want to do is 'Action' in redux.
-
Store : here , Bank is the store... means the basic storage of the values.
-
Type: In actions , we are Depositing the 100rs to the store right? so just we need a format to send the data to the store(bank) The FORMAT is : action
type : payload
where type is the Key and Payload is the Value or can say the Data to be send(i.e 100rs) -
Payload: the data/value that we are sending.
-
Reducer (imp): To update the store, we use the reducer . suppose , action is to add the 100rs to the store. So,basically it takes the state of the Bank(store) i.e 200rs as the previous state and adds the new value ie 100rs to the previous state.
Previous state + Action ( 200 + 100 )
#Note: + is dependent on what type of action you are performing.. here i m doing addition that'y +
-
Dispatch : now how to send that functionality to the store ?? we need something to send that action to the store right ? so for example: we have a button , when we click it , it will do something like do API calls whatever....
So , Dispatch is applied on something that will take that Action to the Store.
Something can be : a button or anyyyy UI thing.
Do :
npm install redux
After this , create a file called index.js// import {createStore} from 'redux'; const redux = require('redux') // createStore const initialState = { amount : 1 } const store = redux.createStore(reducer); function reducer(state=initialState,action){ // now,after line 24 ,this reducer function will have the access inside ACTION if(action.type === "INCREMENT"){ //this should match the exact type : "..." return {amount : initialState.amount+1} } return state; } // get global state console.log(store.getState()); // provides us the GlobalState // action format : {type : "INCREMENT"}; // Dispatch the action. so we have to use : dispatch() from store. // inside that we have to pass the object/data/action with format type:data store.dispatch({type: "INCREMENT"}) // now will check whether changes took place or not console.log(store.getState());
// import {createStore} from 'redux' => for REACT const redux = require('redux') // createStore const initialState = { amount : 1 } const store = redux.createStore(reducer); function reducer(state=initialState,action){ if(action.type === "INCREMENT"){ return {amount : initialState.amount+1} } return state; } // get global state console.log(store.getState()); store.dispatch({type: "INCREMENT"}) console.log(store.getState());
import {createStore , applyMiddleware} from 'redux'; import logger from 'redux-logger'; const initialState = { amount : 1 } // if we are using REDUX in Node, then just we have to write .default while // applying middleware const store = createStore(reducer , applyMiddleware(logger.default)); function reducer(state=initialState,action){ if(action.type === "INCREMENT"){ return {amount : initialState.amount+1} } return state; } console.log(store.getState()); store.dispatch({type: "INCREMENT"}) console.log(store.getState());
import {createStore , applyMiddleware} from 'redux';
import logger from 'redux-logger';
const initialState = {
amount : 1
}
// if we are using REDUX in Node, then just we have to write .default while
// applying middleware
const store = createStore(reducer , applyMiddleware(logger.default));
function reducer(state=initialState,action){
if(action.type === "INCREMENT"){
return {amount : initialState.amount+1}
}
if(action.type === "DECREMENT"){
return {amount : initialState.amount - 1};
}
if(action.type === "INCREMENTByAmount"){
return {amount : initialState.amount + action.payload };
}
return state;
}
// store.dispatch({type: "DECREMENT"}) // decrement amount:1 to amount:0
// store.dispatch({type: "INCREMENTByAmount"}) //this will not work, it will return NaN
store.dispatch({type: "INCREMENTByAmount" , payload : 9})
This ACTIONS {type: "INCREMENTByAmount" , payload : 9}
data can become complicated and need to simplify it.
so , we use ACTION CREATORS
import {createStore , applyMiddleware} from 'redux';
import logger from 'redux-logger';
const initialState = {
amount : 1
}
// if we are using REDUX in Node, then just we have to write .default while
// applying middleware
const store = createStore(reducer , applyMiddleware(logger.default));
// Action Creator:
const increment =()=>{
return {type:"INCREMENT"}
}
const decrement =()=>{
return {type:"DECREMENT"}
}
const INCREMENTByAmount =()=>{
return {type:"INCREMENTByAmount" , payload : 9}
}
function reducer(state=initialState,action){
if(action.type === "INCREMENT"){
return {amount : initialState.amount+1}
}
if(action.type === "DECREMENT"){
return {amount : initialState.amount - 1};
}
if(action.type === "INCREMENTByAmount"){
return {amount : initialState.amount + action.payload };
}
return state;
}
store.dispatch(INCREMENTByAmount())
VSCODE SNIPPET :
import {createStore , applyMiddleware} from 'redux';
import logger from 'redux-logger';
const initialState = {
amount : 1
}
// if we are using REDUX in Node, then just we have to write .default while
// applying middleware
const store = createStore(reducer , applyMiddleware(logger.default));
// Action Creator:
const increment =()=>{
return {type:"INCREMENT"}
}
const decrement =()=>{
return {type:"DECREMENT"}
}
const INCREMENTByAmount =(value)=>{
return {type:"INCREMENTByAmount" , payload : value}
}
function reducer(state=initialState,action){
if(action.type === "INCREMENT"){
return {amount : initialState.amount+1}
}
if(action.type === "DECREMENT"){
return {amount : initialState.amount - 1};
}
if(action.type === "INCREMENTByAmount"){
return {amount : initialState.amount + action.payload };
}
return state;
}
store.dispatch(INCREMENTByAmount(9))
For now , i created a simple db.json file as my basic easy database which returns json.
Let's create a JSON server in node so that we can use it as an API.
Now type : json-server db.json
to start our json file as the server ... it will provide a link.
Now , Install Axios Library to make API calls ,fetch the data..
npm i axios
Now we have to make API call and whatever the value it returns , we have to pass it to the REDUCER with actions(contains the data as we did in the above codes)
import {createStore , applyMiddleware} from 'redux';
import logger from 'redux-logger';
const initialState = {
amount : 1
}
// if we are using REDUX in Node, then just we have to write .default while
// applying middleware
const store = createStore(reducer , applyMiddleware(logger.default));
// Action Creator:
const initUser =(value)=>{
return {type:"INITIAL" ,payload:value}
}
const increment =()=>{
return {type:"INCREMENT"}
}
const decrement =()=>{
return {type:"DECREMENT"}
}
const INCREMENTByAmount =(value)=>{
return {type:"INCREMENTByAmount" , payload : value}
}
function reducer(state=initialState,action){
switch(action.type){
case "INITIAL":
return {amount : action.payload};
case "INCREMENT":
return {amount : initialState.amount+1};
case "DECREMENT":
return {amount : initialState.amount-11};
case "INCREMENTByAmount":
return {amount : initialState.amount + action.payload};
default:
return state;
}
}
store.dispatch(INCREMENTByAmount(899))
Now , we have to MAKE AN API CALL ,so will do : ( in the Index.js node server file)
// API CALL
const getUser=async()=>{
const {data} = await axios.get('http://localhost:3000/account/1')
console.log(data)
}
store.dispatch(getUser())
It will THROW AN ERROR... Its a very common error in Redux coz we are making an API CALL and in redux we can achieve this by using REDUX THUNK
now , When we are using Redux Thunk , we have to pass the FUNCTION and not the Function Call in the Dispatch
like instead of store.dispatch(INCREMENTByAmount())
, we have to pass store.dispatch(INCREMENTByAmount)
and also , we have to pass 2 parameters : dispatch and getState
in the function you are making the API CALLS
Code :
// API CALL
const getUser=async(dispatch,getState)=>{
const {data} = await axios.get('http://localhost:3000/account/1')
console.log(data)
dispatch({type: initUser , payload: data.amount})
}
store.dispatch(getUser)
Now in the above code, we are passing that we want the data at ID = 1 but what if we do it dynamically , whatever the user passes , it should do that particular API CALL
Follow this :
Code :
Here , we did some modification like we have the getUser function , just we have passed the id as the argument and inside this getUser function , we are returning another function which is async and making the API CALL..
This is the best approach to make the API CALLS.
// API CALL
const getUser=(id)=>{
return async(dispatch,getState)=>{
// const {data} = await axios.get(`http://localhost:3000/account/1`)
const {data} = await axios.get(`http://localhost:3000/account/${id}`)
console.log(data)
dispatch({type: initUser , payload: data.amount})
}
}
store.dispatch(getUser(2))
Suppose , in our api we have other field as bonus: