How to dispatch an action on page load in react-redux?

Raj Rj picture Raj Rj · Aug 25, 2016 · Viewed 39.5k times · Source

I have to display a table with lot of data. There is a pagination button which display 10 record per page. I have one button called "FETCH" on-click of it table is populating. How do load my table on load of the page.

action.js

import fetch from 'isomorphic-fetch';
export const ADD_BENEFICIARY = 'ADD_BENEFICIARY';
export const REMOVE_BENEFICIARY = 'REMOVE_BENEFICIARY';

export const ADD_PLAN_TO_COMPARE = 'ADD_PLAN_COMPARE';
export const REMOVE_PLAN_FROM_COMPARE = 'REMOVE_PLAN_COMPARE';
export const SHOW_PLAN_COMPARE = 'SHOW_PLAN_COMPARE';

export const NEXT_PAGE_PLAN_LIST = 'NEXT_PAGE_PLAN_LIST';
export const PREV_PAGE_PLAN_LIST = 'PREV_PAGE_PLAN_LIST';
export const REQUEST_PAGE_PLAN_LIST = 'REQUEST_PAGE_PLAN_LIST';
export const RECEIVE_PAGE_PLAN_LIST = 'RECEIVE_PAGE_PLAN_LIST';

export const showNextPageOfPlans = () => {

  return {
    type: NEXT_PAGE_PLAN_LIST
  }
}

export const showPreviousPageOfPlans = () => {

  return {
    type: PREV_PAGE_PLAN_LIST
  }
}

export const requestPageOfPlans = (startIdx, pageSize) => {

  return {
    type: REQUEST_PAGE_PLAN_LIST,
    start: startIdx,
    pageSize: pageSize
  }
}

export const receivePageOfPlans = (startIdx, json) => {

  return {
    type: RECEIVE_PAGE_PLAN_LIST,
    start: startIdx,
    plans: json
  }
}


export const fetchPlans = (startIdx, pageSize) => {

    var str = sessionStorage.getItem('formValue'); //JSON.stringify(formValues);

  return function (dispatch) {
    dispatch(requestPageOfPlans(startIdx, pageSize));
    return fetch('http://172.16.32.57:9090/alternatePlans/plans/list/', {method: 'post', body: str, headers: new Headers({'Content-Type': 'application/json'})  })
      .then(response => response.json())
      .then(json =>
        dispatch(receivePageOfPlans(startIdx, json))
      )
  }
}

reducer.js

import { REQUEST_PAGE_PLAN_LIST, RECEIVE_PAGE_PLAN_LIST,
         NEXT_PAGE_PLAN_LIST, PREV_PAGE_PLAN_LIST } from './actions';

const initialPaging = {

  startIndex: 0,
  lastIndex: 0,
  pageSize: 10
}

const paging = (state = initialCurrentPage, action) => {

  switch (action.type) {

    case NEXT_PAGE_PLAN_LIST:

      if (state.startIndex+state.pageSize <= state.lastIndex) {

        return { ...state, startIndex: state.startIndex+state.pageSize };
      }
      else {

        return state;
      }

    case PREV_PAGE_PLAN_LIST:

      if (state.startIndex-state.pageSize >= 0) {

        return { ...state, startIndex: state.startIndex-state.pageSize };
      }
      else {

        return state;
      }

    case REQUEST_PAGE_PLAN_LIST:

      return { ...state, isFetching: true };

    case RECEIVE_PAGE_PLAN_LIST:

      return { ...state, isFetching: false };

    default:
      return state;
  }

}

var initialPlans = [];

const plans = (state = initialPlans, action) => {

  switch (action.type) {

    case RECEIVE_PAGE_PLAN_LIST:
      return action.plans.plans;

    default:
      return state;
  }
}


const allReducers = (state = {}, action) => {

  let items = plans(state.plans, action);
  return {
    plans: items,
    paging: paging({ ...initialPaging, ...state.paging, lastIndex: items.length-1 }, action)
  }
}

export default allReducers;

P.S. I am new to react-redux. Official Documentation is good but very less explanation is given.

Answer

agmcleod picture agmcleod · Aug 25, 2016

You call it from the componentDidMount() of the react component for your page, or wherever it makes sense. So in that component file:

import { requestPageOfPlans } from 'actions';
import React from 'react';
import { connect } from 'react-redux';

class MyComponent extends React.Component {
  componentDidMount() {
    this.props.requestPageOfPlans();
  }
}

export default connect((state) => state, { requestPageOfPlans })(MyComponent);

So the key here is the connect setup. The first parameter is how you wish to transform state (your reducers) into data for props. Adjust that as you need to. The second one is what actions you wish to bind. You can also import dispatch manually, but I personally like this pattern. It sets up the actions as props on the component, and you can call it that way. Just pass the arguments to it as you need to. This page here: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options explains the connect function in more detail.

Edit

Given you're paginating on the front end, you'll need to adjust the connect mapStateToProps function to pass the pagination data down to the component, and then loop through it to display what you need. Personally I would do the pagination on the back end, and just do new requests for each page. Depends on how many records you're expecting to have.

So in the connect do something like this:

export default connect((state) => {
  return {
    startIndex: state.paging.lastIndex,
    pageSize: state.paging.pageSize,
    lastIndex: state.paging.lastIndex,
    plans: state.plans
  };
}, { requestPageOfPlans })(MyComponent);

Then in your component, loop through the plans using those indexes:

 render() {
   const plans = [];
   const maxIndex = Math.min(this.props.startIndex + this.props.pageSize, this.props.lastIndex);
   for (let i = this.props.startIndex || 0; i < maxIndex; i++) {
     const plan = this.props.plans[i];
     plans.push(<Plan key={plan.id} plan={plan} />);
   }

   return (
     <ul>{plans}</ul>
   );
 }

Making some assumptions again on how you plan to render it, if you have a component called Plan, etc. But that's roughly how you can work with it.