In this section, we will look into state management of CRUD operations using Redux. To manage and access external resources, Redux-Saga will be used.
What is Redux-Saga?
Redux-Saga is a middleware library used to allow a redux store asynchronously to interact with resources outside of itself. This includes making HTTP requests to external services, accessing browser storage, and executing I/O operations.
Firstly, define actions as follow:
import { GET_POSTS, ADD_POST, DELETE_POST, UPDATE_POST } from "./actionTypes"; export const getPosts = () => { return { type: GET_POSTS, }; }; export const addPost = (data) => { return { type: ADD_POST, payload: data }; }; export const updatePost = (data) => { return { type: UPDATE_POST, payload: data }; }; export const deletePost = (id) => { return { type: DELETE_POST, payload: id }; };
Let's define reducer methods. For an example, getPosts
reducer is defined as follow:
import * as actionType from "../actions/actionTypes"; const initialState = { posts: [] }; export default function (state = initialState, action) { switch (action.type) { case actionType.GOT_POSTS: { return { ...state, posts: action.payload, }; } default: { return { ...state }; } } }
Now, combine all the reducers.
import { combineReducers } from "redux"; import addPost from "./addPost"; import getPosts from "./getPosts"; import updatePost from "./updatePost"; import deletePost from "./deletePost"; export default combineReducers({ addPost, getPosts, updatePost, deletePost });
It's time to define our sagas. Let's do it to fetch blog posts.
Create a getPosts
saga. It works as follow:
- On receiving
GET_POSTS
action it invokesfetchPosts
method.fetchPosts
invokes thegetAll
api service method and pass the response data to another action methodGOT_POSTS
.
import { put, call, takeEvery } from "redux-saga/effects"; import * as actionType from "../actions/actionTypes"; import postsblogPostApi from "../../server/api"; export default function* getPostsSaga() { yield takeEvery(actionType.GET_POSTS, fetchPosts); } function* fetchPosts() { try { const postsResponse = yield call(postsblogPostApi.getAll); yield put({ type: actionType.GOT_POSTS, payload: postsResponse }); } catch (err) { console.log(err); } }
- Add this saga to redux middleware.
import { createStore, applyMiddleware, compose } from "redux"; import createSagaMiddleware from "redux-saga"; import rootReducer from "./reducers/index"; import { getPostsSaga, addPostSaga, deletePostSaga, updatePostSaga } from "./sagas"; const sagaMiddleware = createSagaMiddleware(); const reduxDevTools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(); const middleware = window.__REDUX_DEVTOOLS_EXTENSION__ && process.env.NODE_ENV === "development" ? compose(applyMiddleware(sagaMiddleware), reduxDevTools) : applyMiddleware(sagaMiddleware); export const store = createStore(rootReducer, middleware); sagaMiddleware.run(getPostsSaga); sagaMiddleware.run(addPostSaga); sagaMiddleware.run(updatePostSaga); sagaMiddleware.run(deletePostSaga);
- Now, wrap our
App
component usingProvider
component and pass store redux object. Let's modifyindex.js
file.
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import './index.css'; import App from './App'; import { store } from './redux/store' ReactDOM.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById('root') );
Access redux state
Wrap BlogPost
component with connect
HOC and pass mapStateToProps
and mapDispatchToProps
.
const mapStateToProps = (state) => { return ({ posts: state.getPosts.posts, addedPost: state.addPost.post, deletedPost: state.deletePost.post, updatedPost: state.updatePost.post }) }; const mapDispatchToProps = (dispatch) => ({ actions: { getPosts: () => { dispatch(actionType.getPosts()); }, addPost: (payload) => { dispatch(actionType.addPost(payload)); }, deletePost: (payload) => { dispatch(actionType.deletePost(payload)); }, updatePost: (payload) => { dispatch(actionType.updatePost(payload)); } }, }); export default connect(mapStateToProps, mapDispatchToProps)(BlogPost);
We can get redux states from BlogPost
component's props
object.
const BlogPost = (props) => { const { posts, addedPost, deletedPost, updatedPost, actions } = props; .......
You can find the project here
Project Demo
Top comments (0)