React-Redux-Saga: State management of CRUD operations
Tags: redux, reduxsaga, react, crud
Published: 2021-09-12 21:52:06

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:
```js
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:
```js
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.
```js
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:
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`.

```js
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);
    }
}
```
2. Add this saga to redux middleware.

```js
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);
```

3. Now, wrap our `App` component using `Provider` component and pass store redux object. Let's modify `index.js` file.
```js
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`.
```js
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.
```js
const BlogPost = (props) => {
    const { posts, addedPost, deletedPost, updatedPost,  actions } = props;
.......
```
You can find the project [here](https://github.com/silentrobi/react-redux-saga-crud)
## Project Demo
{% codesandbox react-redux-saga-crud-272yp %}