Flow chart for react-redux -
Understanding how redux work first-
Redux has (always) a single store.
Whenever you want to replace the state in the store, you dispatch an action.
The action is caught by one or more reducers.
The reducer/s create a new state that combines the old state, and the dispatched action.
The store subscribers are notified that there is a new state.
Step 0 - Install redux packages
→ npm i react-redux redux redux-thunk
Step 1 - Creating a redux store
→ create a store.js file in src/app/store.js.
1st way :
src/store.js
src/store.js
import { createStore } from 'redux'
export default configureStore({ reducer: { },})
2nd Way (using combineReducer) - recommended
combineReducers - It combines all the reducers into a single state
import { createStore, combineReducers} from 'redux';
const reducer = combineReducers({
//it will containe all our reducers
})
const store = createStore(reducer)
export default store
Step 2 - Making redux store available to the entire application
→ Include a <Provider />
component, which makes the Redux store available to the rest of your app:
index.js :
---------------
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
Step 2.5 - Installing and setting up redux dev tool chrom extension
→ Install chrome extension - Redux dev tools
→ Install dev tool extension to your project - npm install --save redux-devtools-extension
import { createStore, combineReducers } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
const reducer = combineReducers({
//it will containe all our reducers
})
const store = createStore(
reducer,
composeWithDevTools(///add any store enhancer like redux-thunk,etc here)
)
export default store
→ composeWIthDevTools basically wraps any middleware or store enhancer like redux-thunk, etc
What is Middleware?
Redux middleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more
[Source - Google]
Step 3 : Installing a middleware to enhance our store
→ npm install redux-thunk
→ importing middleware to our store.js
import { createStore, combineReducers, applyMiddleware} from 'redux';
→ add middleware to the store
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(...middleware)))
Final code -
✔ store created
✔ middleware added
✔ combineRedcuer added to aggreagte multiple reducers
✔ chrome extension added to check reducer working
store.js
------------
import { createStore, combineReducers, applyMiddleware} from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
const reducer = combineReducers({
//it will contain all our reducers
})
const middleware = [thunk]
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(...middleware)))
export default store
Step 4: Creating Reducers
→ create a folder "reducers" , then create a file "TodoReducers.js" = src/reducers/TodoReducers
→ What will the reducer do?/*
-> Action ka jo parameter hai wo reducer leta hai taaki store ko update kar sake
-> Action ke andar 2 parameter rehta hai
const exampleAction = {
type : "ADD_TODO", --> helps to judge which switch case i.e action needs to be execute
payload : "Learn redux" --> passes data to update the store (optional)
}
*/
TodoReducers.js
-----------------------
const TodoReducers = (state = {todos : [] }, action) => {
switch(action.type){
case "ADD_TODO" :
return { todos : action.payload}
case "REMOVE_TODO":
return { todos : action.payload}
default :
return state
}
}
→ Assigning reducers to our store
import { TodoReducers } from './reducers/TodoReducers';
const reducer = combineReducers({
Todo : TodoReducers
})
Final Code -
store.js:
---------
import { createStore, combineReducers, applyMiddleware} from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import { TodoReducers } from './reducers/TodoReducers';
const reducer = combineReducers({
Todo : TodoReducers
})
const middleware = [thunk]
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(...middleware)))
export default store
Step 5: Creating Action
→ Create - src/actions/TodoActions.js
→ What will action do?Whenever any action/activity is performed on the application, action is the place where the logic behind it is performed
The action takes two things -
1. dispatch - this is the actual action which takes two arguments -
dispatch({
type: "ADD_TODO",
payload: [{ id: todo, todo }, ...todos],
});
type - it helps reducer to finding which action is called
payload - the actual logic is written when the action is done on application
2. getState - helps to call the global state, so that it can be updated and in turn passed to reducers
→ In our to-do list, we have 2 actions - add data and remove the data.
Keeping that in mind, the actual code
TodoActions.js-
-------------------
//getState helps us to access our app state
//dispatch is the action which passes two agruments action and payload to the reducer
export const AddTodoAction = (todo) => (dispatch, getState) => {
console.log(todo) //this todo is coming from App.js which user is typing on input box
const { Todo: { todos }} = getState(); //this the the gloabla state of our application
console.log(todos)
const hasTodo = todos.find((i) => i.todo === todo); //return boolean
if (!hasTodo && todo !== "") {
dispatch({
type: "ADD_TODO",
payload: [{ id: todo, todo }, ...todos],
});
}
};
export const RemoveTodoAction = (todo) => (dispatch, getState) => {
console.log("remove todo in todoaction folder")
const {
Todo: { todos },
} = getState();
dispatch({
type: "REMOVE_TODO",
payload: todos.filter((t) => t.id !== todo.id),
});
};
Step 6 - Adding the action to our main application
//useDispatch is used to call the action from our application
//useSelector is used to access the global state to our application
App.js:
----------
import "./App.css";
import { TiDelete } from "react-icons/ti";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { AddTodoAction, RemoveTodoAction } from "./actions/TodoActions";
//useDispatch is use to call the action from our application
//useSelector is use to access global state to our application
function App() {
const [todo, setTodo] = useState();
const dispatch = useDispatch();
const Todo = useSelector((state) => state.Todo);
const { todos } = Todo; //Global Todo
const handleSubmit = (e) => {
e.preventDefault();
dispatch(AddTodoAction(todo));
};
return (
<div className="App">
<div className="App-header">
<h2> To-do List (using react-redux) </h2>
<form onSubmit={handleSubmit}>
<input
type="text"
className="enter-todo"
onChange={(e) => setTodo(e.target.value)}
/>
<button type="submit" className="btn">
Add
</button>
</form>
{todos &&
todos.map((eachTodo) => {
if (eachTodo.length <= 1) {
return <span>Cant enter blank todo</span>;
} else {
return (
<ul className="allTodos">
<li key={eachTodo.id} className="singleTodo">
<span fontSize="50px">{eachTodo.todo}</span>
<TiDelete
color="white"
fontSize="30px"
style={{ paddingLeft: 10 }}
onClick={() => dispatch(RemoveTodoAction(eachTodo))}
/>
</li>
</ul>
);
}
})}
</div>
</div>
);
}
export default App;
Step 7 - If you liked it, comment below and follow me on insta - @methimanshu
Some Doubts :
Q > Difference between redux/react-redux/redux-thunk/any others ?
redux - flux like flow with a single store, that can be used in whatever environment you like including vanilla js, react, angular 1/2, etc...
react-redux - bindings between redux and react. The library offers a set of react hooks - useSelector()
, and useStore()
to get the data from the store, and useDispatch()
to dispatch actions. You can also use the connect()
function to create HoCs (higher order components), that listen to the store's state changes, prepare the props for the wrapped component, and re-render the wrapped components when the state changes.
redux-thunk - middleware that allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. Used mainly for async calls to api, that dispatch another action on success / failure.
inshort
- redux: main library (independent from React)
- redux-thunk: a redux middleware which helps you with async actions
- react-redux: connects your redux store with ReactComponents
0 Comments