29

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?

Taxellool
  • 4,063
  • 4
  • 21
  • 38
Denis Bednov
  • 357
  • 1
  • 4
  • 7
  • Redux Saga was developed to solve this kind of problems, [see this answer](https://stackoverflow.com/a/63429981/1554340) – Sid Ali Aug 15 '20 at 19:29

5 Answers5

15

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));
     });
  };
}
Shishir Anshuman
  • 1,115
  • 7
  • 23
pierreg
  • 220
  • 1
  • 9
6

Instead of dispatching an action after a sync action, can you just call the function from the reducer?

So it follows this flow:

Sync action call --> Reducer call ---> case function (reducer) ---> case function (reducer)

Instead of the usual flow which is probably this for you:

Sync action call --> Reducer call

Follow this guide to split the reducers up to see what case reducers are.

If the action you want to dispatch has side affects though then the correct way is to use Thunks and then you can dispatch an action after an action.

Example for Thunks:

export const setSkip = (skip) => {
    return (dispatch, getState) => {

        dispatch(someFunc());
        //Do someFunc first then this action, use getState() for currentState if you want
        return {
            type: 'LIST.SET_SKIP',
            skip: skip
        };
    }
};
Martin Dawson
  • 7,455
  • 6
  • 49
  • 92
  • Thanks for help. Can you provide some example code? (I'm a neebie in react). – Denis Bednov Dec 30 '16 at 08:46
  • @DenisBednov The thunks should work for you if you follow thunks guide. Split your reducers up like in the guide I linked anyway and you will get an idea of what I am talking about. – Martin Dawson Dec 30 '16 at 08:51
1

also check this out redux-sequence-action

zarehb
  • 21
  • 7
0

Thanks for the replies, but I made it this way:

let top = this.props.list.top;
let skip = this.props.list.skip;
let newSkip = skip + top;

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

First I calculate new skip and dispatch an async action with this new value. Then I dispatch a syns action, which updates skip in state.

Denis Bednov
  • 357
  • 1
  • 4
  • 7
-1

dispatch({ type: 'LIST.SUCCESS', data: data, skip: The value you want after sync action });

ryouaki
  • 19
  • 4