💥💥 React Redux Example 💥💥
This is a todo project for understanding the concepts of redux in react, this github project is referenced in this project
What is Redux ?
Redux is used for state management for the application. It's main advantage is to overcome the problem of "props drilling" among the components.
For example, Let's assume we have 4 component named A,B,C,D and their representation is like :
A ( Parent Component )
|
B
|
C
|
D ( Leaf Component )
and we have a prop named itemCode which is generated at component A, and only to be used at component D.
Traditional Way
was to pass that itemCode as an prop to B, then C, and at last to D.
😎😎 How Redux Solves
is that it makes an store for an application, which holds all the states of application at one place. So when itemCode is generated at component A, insted of passing it as an props to all the way down to component D, component A will store that itemCode in the Store, and component D will fetch itemCode value form that Store.
Note, But what's the problem in props 🙄🙄 ?
This todo application is very small scale project, in large projects, this props count be large like 10, 20, 100 anything, so using props everywhere will be make the application very very complex 🤯🤯🤯
Let's drive deep into working of Redux
First let's setup the basic project
- Create new react project
npx create-react-app todo_redux
- Install redux dependencies
npm install react-redux redux
- Make an folder named action and reducer in
/src
- Inside action folder, make 2 files,
/action-types.js
and/todo.js
- Inside reducer folder, make file named
/todo.js
- And in /src folder a file, make a file named
store.js
After this your project heirarchy will look like :
But what are these Action, Reducer, and Store ?
💥💥 Actions 💥💥 :
It contains the logic that will tell Reducer what should be done
on calling specific commands which developer has made. Like in our case, their are 2 action which is made,
- Add Todo
- Remove Todo
So, Action will tell Reducer that, Okay so there is an call from component to Add Todo, So Hey Reducer, we now have to Add an todo with this that details.
Syntax for Action :
import { ADD_TODO } from "./action-types";
export const addTodo = (todo) => ({
type: ADD_TODO,
payload: todo,
});
addTodo is a name of the package which return object with a compulsory field **"type"** and optional field "payload".
- Type : It is used to validate action on reducer side that okay an action of type blah blah 😜 type is recieved and I have to perform logic related to this blah blah 🙈 only
- Payload : Sometimes on the reducer side, some data is sent which is used to update the state in the store.
💥💥 Reducer 💥💥 :
So till now we have an action which states what to do, but how to do ?
is defined in reducer file. For our case, what to do with the state/store when an addTodo action is recieved == We have to add an todo with details recieved from action package into out store which has some previous todos and return the updated state of todos in out store.
Syntax for Reducer
import { ADD_TODO } from "../action/action-types";
const initialState = [];
export const todos = (state = initialState, action) => {
switch (action.type) {
case ADD_TODO:
return [...state, action.payload];
default:
return state;
}
};
See here the types field of action comes into play, to validate what logic is to be performed when an certain type of action is called. And payload data to update the state/store.
There can be many files containing multiple reducers, but at the end we will combine all the reducers from all the files into one root reducer, because the store expects only one reducer. ( we will see how to do that later in this article )
💥💥 Store 💥💥 :
Store is the place where all the states of an application is kept. Store is readonly , for updating, we can only do it through reducer
And also, for an whole application, there will be only 1 store.
Syntax for Store
import { createStore, combineReducers } from "redux";
import { todos } from "./reducer/todo";
const rootReducer = combineReducers(
todos
});
const store = createStore(rootReducer);
export default store;
Here we import all the reducer file and with the help of combineReducers
we combine them into 1 reducer and with createStore
we create an store for the application.
So till now we have made an Store
with root reducers combining all the reducers, Action
which tells what to do and Reducer
which tells how to do. Now the question is how to access store from component ? 🤷♀️🤷♀️🤷♀️
Firstly we have to wrap the main parent component inside App.js with
<Provider store={store}> all the components comes here </Provider >
Provider is react-redux
magic which handles all the work and store is passed it, which is imported from store file.
Now connecting component to store ✌✌ :
We have to use 2 function which will fetch and sent the data to store through action then reducers all that flow.
Introducing :
mapStateToProps( ) 🤑🤑:
This function is used to fetch the data from store and pass it as a prop to the component, and from then onwards in the component it is used as traditional way like using value from props.
Syntax for mapStateToProps()
const mapStateToProps = (state) => ({
todos: state.todos,
});
and in component, it will be accessible as props
const TodoForm = ({ todos }) => {};
mapDispatchToProps ( ) 😁😁:
This function is used to prepare action package which will later on go to reducer to update the state of the application. For example in our case, we have to add todo with todo detail so we have to prepare action of type addtodo
Syntax for mapDispatchToProps ()
const mapDispatchToProps = (dispatch) => ({
addTodo: (todo) => {
dispatch(addTodo(todo));
},
});
and in component, it will be accessible as props
const TodoForm = ({ addTodo }) => {};
Top comments (2)
Genuinely curious, besides having to work on older codebases, why use redux when zustand can do the same thing in half the lines of codes and half of the time to do it?
I don't know zustand in depth, but, beyond redux be the default choice in professional applications, redux brings much more possibilities than only state management. For example redux thunk, redux sagas, redux persist.. this libs offer ways to remove the logic out of the component files, and this improove the organization of the codebase