DEV Community

Mohammad Abu Musa RABIUL
Mohammad Abu Musa RABIUL

Posted on

3

React-Redux-Saga: State management of CRUD operations

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
    };
};
Enter fullscreen mode Exit fullscreen mode

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 };
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
});

Enter fullscreen mode Exit fullscreen mode

It's time to define our sagas. Let's do it to fetch blog posts.
Create a getPosts saga. It works as follow:

  1. On receiving GET_POSTS action it invokes fetchPosts method. fetchPosts invokes the getAll api service method and pass the response data to another action method GOT_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);
    }
}
Enter fullscreen mode Exit fullscreen mode
  1. 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);
Enter fullscreen mode Exit fullscreen mode
  1. Now, wrap our App component using Provider component and pass store redux object. Let's modify index.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')
);

Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

We can get redux states from BlogPost component's props object.

const BlogPost = (props) => {
    const { posts, addedPost, deletedPost, updatedPost,  actions } = props;
.......
Enter fullscreen mode Exit fullscreen mode

You can find the project here

Project Demo

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up