BinaryMuse / fluxxor

:hammer_and_wrench: Flux architecture tools for React
http://fluxxor.com/
MIT License
1.69k stars 154 forks source link

Wait until async request completes #146

Closed vishaltelangre closed 9 years ago

vishaltelangre commented 9 years ago

I have a form with submit button. On form submit, I want to disable the submit button (with loading status) until the async ajax request (which is submitting form data to server) completes (either succeed or fails). If request succeeds, I want to go to url with id of created resource (on server). I am using react-router v1.x (i.e. dynamic routes). How it can be done with fluxxor?

Following is a dummy example snippet to elaborate above problem:

var FormComponent = React.createClass({
mixins:  [
  History,
    Fluxxor.FluxMixin(React),
    Fluxxor.StoreWatchMixin("resource")
  ],

  getStateFromFlux: function() {
    // How to know whether submitted data request completed or not?
    // Or maybe following is the way?
    var lastSubmitted = this.getFlux().store("resource").getLastSubmitted();
    var lastSubmiitedID = lastSubmitted.id;
    if(lastSubmittedID !== PROGRESS_STATUS && lastSubmiitedID !== undefined) {
      history.replaceState("/resources/" + lastSubmitted.id);
      return;
    }

    return {
      submitting: lastSubmittedID === PROGRESS_STATUS
    };
  },

  onSubmit: function() {
    // omitted
    this.getFlux().actions.resource.add(data);
  },

  render: function() {
    return (
      <form>
        // omitted
        <SubmitButton submitting={this.state.submitting} />
      </form>
    )
  }
})

With traditional approach, I could have passed an async request promise to the component, which after resolving would yield the predictable status, and until it resolves, I could stay on same component displaying submitting status, and transit to created resource's url if request succeeds.

Beside -- FYI, I am able to show spinner while an async request for list of a resource completes. But above problem is very different, IMO.

I have also checked #112, and Dealing with Asynchronous Data, which are close but doesn't seem to fit for my problem.

I have actions, stores, constants, etc. all set. Please let me know if you need more on this, I can elaborate and provide more details.

BinaryMuse commented 9 years ago

Have you seen the discussion at #132, specifically my initial comment? I still think returning a promise from your action creators or passing in a callback is probably the most straightforward way to go:

Finally, I'm still not convinced the technique I originally used for the React Router example (before changing it) is actually that bad a practice; generally actions should be fire-and-forget, but for very side-effecty things like routing I'm not as much of a stickler:

  doThing: function() {
    flux.actions.thing.create(this.state.data, function(id) {
      this.context.router.transitionTo("/things/" + id);
    }.bind(this));
  },

  contextTypes: {
    router: React.PropTypes.object
  },
vishaltelangre commented 9 years ago

@BinaryMuse: Thanks, this approach looks neat.