Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Calling an Action returns a Promise #112

Closed
echenley opened this issue Nov 6, 2014 · 9 comments
Closed

Feature Request: Calling an Action returns a Promise #112

echenley opened this issue Nov 6, 2014 · 9 comments

Comments

@echenley
Copy link

echenley commented Nov 6, 2014

It would be very handy to have the ability to execute functions on completion of an Action, allowing nice things like executing UI code inline:

postActions.submitPost(post).then(function() {
    this.transitionTo('home');
}.bind(this));

Promises would ideally be resolved when a Store triggers an event. This would allow for asynchronous behavior in the Stores:

var postStore = Reflux.createStore({
    init: function () {
        this.posts = {};
        databaseRef.on('child_added', function(posts) {
            this.posts = posts.val();
            this.trigger(this.posts); // promise is resolved here
        }.bind(this));
    },
    submitPost: function (post) {
        // asynchronous push to database
        databaseRef.push(post);
    }
});
@WRidder
Copy link

WRidder commented Nov 6, 2014

Interesting idea. However, if I'm correct, you have to be careful to not undermine the idea of a single data flow. By this I mean that most uses of promises may prevent the (proper?) use of actions.

For example, let's take the submit post use case where I would normally use two actions: submitPost and postSaved for instance to track this async backend request. Using promises I could just use the promise returned by the submitPost action.

I'm new to Reflux and still figuring it out so I might very well be wrong about this.

@echenley
Copy link
Author

echenley commented Nov 6, 2014

I was thinking the same thing with regard to data flow. Changed it to a userStore example because that makes more sense. After some wiggling, I figured out that a more Reflux-y way of doing it is this:

var React = require('react/addons');
var Reflux = require('reflux');

var Navigation = require('react-router').Navigation;
var userActions = require('../actions/userActions');
var userStore = require('../stores/userStore');

var Login = React.createClass({

    mixins: [Navigation, Reflux.ListenerMixin],

    componentDidMount: function () {
        this.listenTo(userStore, function () {
            this.transitionTo('home');
        }.bind(this));
    },

    signIn: function (e) {
        e.preventDefault();
        userActions.signIn({
            email: this.refs.email.getDOMNode().value.trim(),
            password: this.refs.password.getDOMNode().value.trim()
        });
    },

    // render, etc.
});

@echenley
Copy link
Author

echenley commented Nov 6, 2014

In my case, posts are a little more tricky since the postStore triggers an event every time a new post is added to the Store; it's not necessarily the user's action that caused it. One solution might be a separate userPostStore to trigger user-specific Post events?

@WRidder
Copy link

WRidder commented Nov 6, 2014

That might indeed be a decent approach. Since you can indeed receive posts from the backend for instance (using sockets/polling).

Tomorrow I'll start working on setting up a sample application which should resemble a small community website (so more involved than the basic todo app). Think about pages, discussions and the like. I would like to figure out some best practices using reactjs + reflux with regards to routing, permissions, pages, real-time data (sockets), server-side rendering. Just to cover all the basics. Will keep you guys posted.

@krawaller
Copy link
Contributor

It's not prepped for public eyes, but here's the innards of a recent app of mine; I have a loginStore which triggers with a username or undefined whenever the user logs in or out, and the loginButton then listens to that store (as does some other components).

I agree with the sentiment that a Store should control just one thing. My app also has a userStore, a chatStore, etc.

You can see the app live here, but as you can't login since it combines Github auth with checking against a hardcoded array, some of the functionality will be untestable to you (logged in users can chat and edit their info).

Maybe too general, but I also wrote a post on the Reflux data flow which might help.

@WRidder
Copy link

WRidder commented Nov 8, 2014

@krawaller thanks! That makes for some nice reference. Thumbs up for the blog posts as well, good reads.

@echenley
Copy link
Author

echenley commented Nov 8, 2014

👍 Thanks y'all.

@spoike
Copy link
Member

spoike commented Nov 10, 2014

I guess everyone is in agreement, that you should rely on change events from stores instead.

While it'd be nice to see when an action is done, it's much more flux:y to wait for the affected stores to update instead of when the action is completely done. It's more in line with data-flow thinking where components and stores only care about data coming in and occasionally initiate new data flows by invoking actions.

I'll close this for now.

@spoike spoike closed this as completed Nov 10, 2014
@ericclemmons
Copy link
Contributor

@spoike I originally agreed with the logic, but it makes sense to utilize a promise particularly with react-router:

https://github.com/rackt/react-router/blob/master/docs/api/components/RouteHandler.md#static-lifecycle-methods

var Person = React.createClass({
  statics: {
    willTransitionTo: function(transition, params) {
      transition.wait(PersonStore.fetch({ id: params.id }));
    }
  },

  getInitialState: function() {
    return {
      person: PersonStore.find({ id: this.getParams().id }),
    };
  },
  ...
});

It's worth strongly encouraging actions to be the primary method of communication, but this would effectively allow people to do the equivalent of angular-router's resolve with Reflux + React.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants