We now have a youtube channel. Subscribe!

ReactJS | State Management (Example)



Hello folks! welcome back to a new section of our tutorial on ReactJS. In this section of our tutorial on ReactJS, we will be studying about ReactJS State Management.

We will perform below actions to manage our redux store.

  • Fetching the expenses from the server via async fetch api and set it in Redux store.
  • Add new expense to the server via async fetch programming and then add the new expense in the Redux store.
  • Deleting existing expense from the server via async fetch api and update the Redux store.

Let us create an action type, action creator, actions and reducers to manage the Redux state.

Create a folder, actions under src folder.

Next, create a file, types.js to create action types.

export const LIST_EXPENSE_STARTED = 'LIST_EXPENSE_STARTED';
export const LIST_EXPENSE_SUCCESS = 'LIST_EXPENSE_SUCCESS';
export const LIST_EXPENSE_FAILURE = 'LIST_EXPENSE_FAILURE';

export const ADD_EXPENSE_STARTED = 'ADD_EXPENSE_STARTED';
export const ADD_EXPENSE_SUCCESS = 'ADD_EXPENSE_SUCCESS';
export const ADD_EXPENSE_FAILURE = 'ADD_EXPENSE_FAILURE';

export const DELETE_EXPENSE_STARTED = 'DELETE_EXPENSE_STARTED';
export const DELETE_EXPENSE_SUCCESS = 'DELETE_EXPENSE_SUCCESS';
export const DELETE_EXPENSE_FAILURE = 'DELETE_EXPENSE_FAILURE';

Next, create a file, index.js beneath actions folder to create action creators.

import {
   LIST_EXPENSE_STARTED, LIST_EXPENSE_SUCCESS, LIST_EXPENSE_FAILURE,
   ADD_EXPENSE_STARTED, ADD_EXPENSE_SUCCESS, ADD_EXPENSE_FAILURE,
   DELETE_EXPENSE_STARTED, DELETE_EXPENSE_SUCCESS, DELETE_EXPENSE_FAILURE,
} from "./types";
export const getExpenseListStarted = () => {
   return {
      type: LIST_EXPENSE_STARTED
   }
}
export const getExpenseListSuccess = data => {
   return {
      type: LIST_EXPENSE_SUCCESS,
      payload: {
         data
      }
   }
}
export const getExpenseListFailure = error => {
   return {
      type: LIST_EXPENSE_FAILURE,
      payload: {
         error
      }
   }
}
export const addExpenseStarted = () => {
   return {
      type: ADD_EXPENSE_STARTED
   }
}
export const addExpenseSuccess = data => {
   return {
      type: ADD_EXPENSE_SUCCESS,
      payload: {
         data
      }
   }
}
export const addExpenseFailure = error => {
   return {
      type: ADD_EXPENSE_FAILURE,
      payload: {
         error
      }
   }
}
export const deleteExpenseStarted = () => {
   return {
      type: DELETE_EXPENSE_STARTED
   }
}
export const deleteExpenseSuccess = data => {
   return {
      type: DELETE_EXPENSE_SUCCESS,
      payload: {
         data
      }
   }
}
export const deleteExpenseFailure = error => {
   return {
      type: DELETE_EXPENSE_FAILURE,
      payload: {
         error
      }
   }
}

Here, we created an action creator for every possible results (success, failure and error) of fetch api. Since we are going to use three web api calls and each call is going to have three possible outcomes, we make use of 9 action creators.

Next, create a file, expenseActions.js under actions folder and create three functions to fetch, add and delete expenses and to also dispatch state changes.

import {
   getExpenseListStarted, getExpenseListSuccess, getExpenseListFailure,
   addExpenseStarted, addExpenseSuccess, addExpenseFailure,
   deleteExpenseStarted, deleteExpenseSuccess, deleteExpenseFailure
} from "./index";
export const getExpenseList = () => async dispatch => {
   dispatch(getExpenseListStarted());
   try {
      const res = await fetch('http://localhost:8000/api/expenses');
      const data = await res.json();
      var items = [];
      data.forEach((item) => {
         let newItem = {
            id: item._id,
            name: item.name,
            amount: item.amount,
            spendDate: item.spend_date,
            category: item.category
         }
         items.push(newItem)
      });
      dispatch(getExpenseListSuccess(items));
   } catch (err) {
      dispatch(getExpenseListFailure(err.message));
   }
}
export const addExpense = (data) => async dispatch => {
   dispatch(addExpenseStarted());

   let newItem = {
      name: data.name,
      amount: data.amount,
      spend_date: data.spendDate,
      category: data.category
   }
   console.log(newItem);
   try {
      const res = await fetch('http://localhost:8000/api/expense', {
         method: 'POST',
         body: JSON.stringify(newItem),
         headers: {
            "Content-type": "application/json; charset=UTF-8"
         } 
      });
      const data = await res.json();
      newItem.id = data._id;
      dispatch(addExpenseSuccess(newItem));
   } catch (err) {
      console.log(err);
      dispatch(addExpenseFailure(err.message));
   }
}
export const deleteExpense = (id) => async dispatch => {
   dispatch(deleteExpenseStarted());
   try {
      const res = await fetch('http://localhost:8000/api/expense/' + id, {
         method: 'DELETE'
      });
      const data = await res.json();
      dispatch(deleteExpenseSuccess(id));
   } catch (err) {
      dispatch(deleteExpenseFailure(err.message));
   }
}


Here,

  • Used async fetch api to do web api calls.
  • Used dispatch function to dispatch proper action during success, failure and error events.

Create a folder, reducer under src folder and create a file, index.js under reducer folder to create Redux reducers.

import {
   LIST_EXPENSE_STARTED, LIST_EXPENSE_SUCCESS, LIST_EXPENSE_FAILURE,
   ADD_EXPENSE_STARTED, ADD_EXPENSE_SUCCESS, ADD_EXPENSE_FAILURE,
   DELETE_EXPENSE_STARTED, DELETE_EXPENSE_SUCCESS, DELETE_EXPENSE_FAILURE
} from "../actions/types";

// define initial state of user
const initialState = {
   data: null,
   loading: false,
   error: null
}
export default function expenseReducer(state = initialState, action) {
   switch (action.type) {
      case LIST_EXPENSE_STARTED:
         return {
            ...state,
            loading: true
         }
      case LIST_EXPENSE_SUCCESS:
         const { data } = action.payload;
         return {
            ...state,
            data,
            loading: false
         }
      case LIST_EXPENSE_FAILURE:
         const { error } = action.payload;
         return {
            ...state,
            error
         }
      case ADD_EXPENSE_STARTED:
         return {
            ...state,
            loading: true
         }
      case ADD_EXPENSE_SUCCESS:
         return {
            ...state,
            loading: false
         }
      case ADD_EXPENSE_FAILURE:
         const { expenseError } = action.payload;
         return {
            ...state,
            expenseError
         }
      case DELETE_EXPENSE_STARTED:
         return {
            ...state,
            loading: true
         }
      case DELETE_EXPENSE_SUCCESS:
         return {
            ...state,
            data: state.data.filter(expense => expense.id !== action.payload.data),
            loading: false
         }
      case DELETE_EXPENSE_FAILURE:
         const { deleteError } = action.payload;
         return {
            ...state,
            deleteError
         }
      default:
         return state
   }
}

Here, we have updated the redux store state for each action type.

Next, open index.js file under src folder and include Provider component so that all the components can connect and work with the redux store.

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import rootReducer from './reducers';
import App from './components/App';

const store = createStore(rootReducer, applyMiddleware(thunk));

ReactDOM.render(
   <Provider store={store}>
      <App />
   </Provider>,
   document.getElementById('root')
);

Here,

  • We have imported createStore and applymiddlewa
  • Imported thunk from the redux-thunk library (for async fetch api)
  • Imported Provider from redux library
  • Created newstore using createStore by configuring the reducer and thunk middleware
  • Attached the Provider component as top level component with redux store


Alright guys! This is where we are going to be rounding up for this tutorial. In our next tutorial, we will be studying about ReactJS List Expenses (Example).

Feel free to ask your questions where necessary and we will attend to them as soon as possible. If this tutorial was helpful to you, you can use the share button to share this tutorial.

Follow us on our various social media platforms to stay updated with our latest tutorials. You can also subscribe to our newsletter in order to get our tutorials delivered directly to your emails.

Thanks for reading and bye for now.

Post a Comment

Hello dear readers! Please kindly try your best to make sure your comments comply with our comment policy guidelines. You can visit our comment policy page to view these guidelines which are clearly stated. Thank you.
© 2022 ‧ WebDesignTutorialz. All rights reserved. Developed by Jago Desain