React / reflux如何进行正确的异步调用

时间:2015-06-12 15:18:30

标签: javascript asynchronous reactjs react-jsx refluxjs

我最近开始学习ReactJS,但我对异步调用感到困惑。

假设我有一个带有用户/通行证字段和登录按钮的登录页面。组件看起来像:

var Login = React.createClass({

    getInitialState: function() {
        return {
            isLoggedIn: AuthStore.isLoggedIn()
        };
    },

    onLoginChange: function(loginState) {
        this.setState({
            isLoggedIn: loginState
        });
    },

    componentWillMount: function() {
        this.subscribe = AuthStore.listen(this.onLoginChange);
    },

    componentWillUnmount: function() {
        this.subscribe();
    },

    login: function(event) {
        event.preventDefault();
        var username = React.findDOMNode(this.refs.email).value;
        var password = React.findDOMNode(this.refs.password).value;
        AuthService.login(username, password).error(function(error) {
            console.log(error);
        });
    },

    render: function() {

        return (
                <form role="form">
                    <input type="text" ref="email" className="form-control" id="username" placeholder="Username" />
                    <input type="password" className="form-control" id="password" ref="password" placeholder="Password" />
                    <button type="submit" className="btn btn-default" onClick={this.login}>Submit</button>
                </form>
        );
    }
});

AuthService看起来像:

module.exports = {
    login: function(email, password) {
        return JQuery.post('/api/auth/local/', {
            email: email,
            password: password
        }).success(this.sync.bind(this));
    },

    sync: function(obj) {
        this.syncUser(obj.token);
    },

    syncUser: function(jwt) {
        return JQuery.ajax({
            url: '/api/users/me',
            type: "GET",
            headers: {
                Authorization: 'Bearer ' + jwt
            },
            dataType: "json"
        }).success(function(data) {
            AuthActions.syncUserData(data, jwt);
        });
    }
};

操作:

var AuthActions = Reflux.createActions([
  'loginSuccess',
  'logoutSuccess',
  'syncUserData'
]);

module.exports = AuthActions;

并存储:

var AuthStore = Reflux.createStore({
    listenables: [AuthActions],

    init: function() {
        this.user = null;
        this.jwt = null;
    },

    onSyncUserData: function(user, jwt) {
        console.log(user, jwt);
        this.user = user;
        this.jwt = jwt;
        localStorage.setItem(TOKEN_KEY, jwt);
        this.trigger(user);
    },

    isLoggedIn: function() {
        return !!this.user;
    },

    getUser: function() {
        return this.user;
    },

    getToken: function() {
        return this.jwt;
    }
});

因此,当我点击登录按钮时,流程如下:

Component -> AuthService -> AuthActions -> AuthStore

我直接使用AuthService.login调用AuthService。

我的问题是我做得对吗?

我应该使用操作preEmit并执行:

var ProductAPI = require('./ProductAPI')
var ProductActions = Reflux.createActions({
  'load',
  'loadComplete',
  'loadError'
})

ProductActions.load.preEmit = function () {
     ProductAPI.load()
          .then(ProductActions.loadComplete)
          .catch(ProductActions.loadError)
}

问题是preEmit是它使组件的回调更复杂。我想学习正确的方法,并找到用ReactJS / Reflux堆栈放置后端调用的位置。

3 个答案:

答案 0 :(得分:6)

我也在使用Reflux,我使用不同的方法进行异步调用。

在vanilla Flux中,异步调用将放入操作中。

enter image description here

但在Reflux中,异步代码在商店中表现最佳(至少在我看来是这样):

enter image description here

所以,特别是在你的情况下,我会创建一个名为&#39; login&#39;它将由组件触发并由将启动登录过程的商店处理。一旦握手结束,商店将在组件中设置一个新状态,让它知道用户已登录。同时(例如this.state.currentUser == null)组件可能会显示加载指示符。

答案 1 :(得分:1)

对于Reflux,你应该看看https://github.com/spoike/refluxjs#asynchronous-actions

那里描述的简短版本是:

1)不要使用PreEmit钩子

2)使用异步操作

var MyActions = Reflux.createActions({

    "doThis" : { asyncResult: true },
    "doThat" : { asyncResult: true }

});

这不仅会创建&#39; makeRequest&#39;行动,但也做了很多事情,然后做了很多事情,并且做了很多事情。并且&#39; doThat.failed&#39;动作。

3)(可选,但首选)使用promises来调用动作

MyActions.doThis.triggerPromise(myParam)
  .then(function() {
    // do something
    ...
    // call the 'completed' child
    MyActions.doThis.completed()
 }.bind(this))
 .catch(function(error) {
   // call failed action child
   MyActions.doThis.failed(error);
 });

我们最近重写了我们的所有行动,并且预先发布了#39;挂钩到这个模式,并像结果和结果代码。

答案 2 :(得分:0)

我也发现异步回流有点令人困惑。来自facebook的原始流量,我会做这样的事情:

var ItemActions = {
  createItem: function (data) {
    $.post("/projects/" + data.project_id + "/items.json", { item: { title: data.title, project_id: data.project_id } }).done(function (itemResData) {
      AppDispatcher.handleViewAction({
        actionType: ItemConstants.ITEM_CREATE,
        item: itemResData
      });
    }).fail(function (jqXHR) {
      AppDispatcher.handleViewAction({
        actionType: ItemConstants.ITEM_CREATE_FAIL,
        errors: jqXHR.responseJSON.errors
      });
    });
  }
};

因此该操作执行ajax请求,并在完成后调用调度程序。我在preEmit模式上也不大,所以我只想在商店使用处理程序:

var Actions = Reflux.createActions([
  "fetchData"
]);

var Store = Reflux.createStore({
  listenables: [Actions],

  init() {
    this.listenTo(Actions.fetchData, this.fetchData);
  },

  fetchData() {
    $.get("http://api.com/thedata.json")
      .done((data) => {
        // do stuff
      });
  }
});

我从商店做这件事并不大,但考虑到回流如何将行动抽象出去,并且会不断激发listenTo回调,我很好。更容易理解我如何将回调数据设置到商店中。仍然保持单向。