React Redux dispatch action after another action

Denis Bednov picture Denis Bednov · Dec 30, 2016 · Viewed 44.8k times · Source

I have an async action, which fetch data from REST API:

export const list = (top, skip) => dispatch => {
    dispatch({ type: 'LIST.REQUEST' });

    $.get(API_URL, { top: top, skip: skip })
        .done((data, testStatus, jqXHR) => {
            dispatch({ type: 'LIST.SUCCESS', data: data });
        });
};

A sync action, which changes skip state:

export const setSkip = (skip) => {
    return {
        type: 'LIST.SET_SKIP',
        skip: skip
    };
};

Initial state for top = 10, skip = 0. In component:

class List extends Component {
    componentDidMount() {        
        this.list();
    }

    nextPage() {
        let top = this.props.list.top;
        let skip = this.props.list.skip;

        // After this 
        this.props.onSetSkip(skip + top);

        // Here skip has previous value of 0.
        this.list();
        // Here skip has new value of 10.
    }

    list() {
        this.props.List(this.props.list.top, this.props.list.skip);
    }

    render () {
        return (
            <div>
                <table> ... </table>
                <button onClick={this.nextPage.bind(this)}>Next</button>
            </div>
        );
    }
}

When button Next at first time clicked, value of skip which uses async action not changed. How I can to dispatch action after sync action?

Answer

pierreg picture pierreg · Jan 25, 2017

If you are using redux thunk, you can easily combine them. It's a middleware that lets action creators return a function instead of an action.

Your solution might have worked for you now if you don't need to chain the action creators and only need to run both of them.

this.props.onList(top, newSkip);
this.props.onSetSkip(newSkip);

If you need chaining(calling them in a synchronous manner) or waiting from the first dispatched action's data, this is what I'd recommend.

export function onList(data) {
  return (dispatch) => {
          dispatch(ONLIST_REQUEST());
    return (AsyncAPICall)
    .then((response) => {
      dispatch(ONLIST_SUCCESS(response.data));
    })
    .catch((err) => {
      console.log(err);
    });
  };
}

export function setSkip(data) {
      return (dispatch) => {
              dispatch(SETSKIP_REQUEST());
        return (AsyncAPICall(data))
        .then((response) => {
          dispatch(SETSKIP_SUCCESS(response.data));
        })
        .catch((err) => {
          console.log(err);
        });
      };
    }

export function onListAndSetSkip(dataForOnList) {
  return (dispatch) => {
     dispatch(onList(dataForOnList)).then((dataAfterOnList) => {
       dispatch(setSkip(dataAfterOnList));
     });
  };
}