Skip to content

Instantly share code, notes, and snippets.

@rickharrison
Last active October 2, 2015 18:07
Show Gist options
  • Select an option

  • Save rickharrison/39e9e0ad15f7eafdde1b to your computer and use it in GitHub Desktop.

Select an option

Save rickharrison/39e9e0ad15f7eafdde1b to your computer and use it in GitHub Desktop.

I have a question around handling actions for asynchronous requests to an API. Imagine that you have a middleware, which will hit an API and fire off 3 actions as is common in best practice redux/flux. One for the initial request, one for success, and one for failure. Typically you can set a fetching flag and store an error if there is one.

Here is some basic example pseudo-ish code demonstrating this:

import {
  CREATE_FOO_REQUEST,
  CREATE_FOO_SUCCESS,
  CREATE_FOO_FAILURE
} from './actions';

const initialState = {
  entity: null,
  isFetching: false,
  error: null
}

export default function foo (state = initialState, action) {
  switch (action.type) {
    case CREATE_FOO_REQUEST:
      return {
        ...state,
        isFetching: true,
        error: null
      };

    case CREATE_FOO_SUCCESS:
      return {
        ...state,
        entity: action.payload,
        isFetching: false,
        error: null
      };

    case CREATE_FOO_FAILURE:
      return {
        ...state,
        isFetching: false,
        error: action.payload
      };
  }
}
const FooList = React.createClass({
  handleSubmit: function (event) {
    event.preventDefault();
    
    // validate data
    
    this.props.createFooResource({ field1, field2 });
  }

  render: function () {
    if (this.props.isFetching) {
      return <p>Loading...</p>;
    }
    
    if (this.props.error) {
      return <p>Error: {this.props.error}</p>
    }
    
    return <form>...</form>;
  }
});

function mapStateToProps (state) {
  return {
    isFetching: state.foo.isFetching,
    error: state.foo.error
  };
}

const mapDispatchToProps = {
  createFooResource
};

export default connect(mapStateToProps, mapDispatchToProps)(FooComponent);

My question is how do you know in the component that the action is completed and you can now either display a success message or transition to another page using react-router. It is extremely easy to listen for the loading and error flags, but how do you know when a request has gone through successfully and to do something. A naive approach when not using redux/flux would look like this:

handleSubmit: function () {
  createFooResource().then(function () {
    this.history.replaceState(...);
  }).catch((err) => {
    this.setState({ error: err });
  })
}

What is the best practice to know when something is completed in redux with the typical 3 actions for asynchronous behavior?

@takempf
Copy link

takempf commented Oct 2, 2015

One potential "solution" for the persistent error is to explicitly set it to null inside getInitialState, then pull it from the store normally on change.

@takempf
Copy link

takempf commented Oct 2, 2015

You could also have an action that fires when the form initializes and resets any old state.

@takempf
Copy link

takempf commented Oct 2, 2015

In our current setup...

  getStateFromStores: function () {
    var state = {
      user: UserStore.getUser(),
      loading: UserStore.isUpdatingProfile(),
      error: this.initialized ? UserStore.getUpdatingProfileError() : null
    };
    this.initialized = true;
    return state;
  },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment