【问题标题】:React/reflux how to do proper async callsReact/reflux 如何进行正确的异步调用
【发布时间】:2015-08-28 16:11:58
【问题描述】:

我最近开始学习 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 堆栈找到放置后端调用的位置。

【问题讨论】:

    标签: javascript asynchronous reactjs react-jsx refluxjs


    【解决方案1】:

    我也在使用 Reflux,并且我对异步调用使用了不同的方法。

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

    但在 Reflux 中,异步代码在商店中效果最好(至少在我看来):

    因此,特别是在您的情况下,我将创建一个名为“登录”的操作,该操作将由组件触发并由将启动登录过程的商店处理。握手结束后,商店将在组件中设置一个新状态,让其知道用户已登录。同时(例如,this.state.currentUser == null)组件可能会显示加载指示器。

    【讨论】:

    • 感谢您的回答。您如何看待stackoverflow.com/questions/28012356/… 这种做法actions.init.listen?因为我做了一个研究,很多人都在按照你的方式做,但也有很多人在行动中做。所以我很困惑,无法决定使用哪种模式。
    • 嗯,人们使用它的方式有所不同,因为对于 Reflux,没有“正确的方式”。这实际上取决于您希望如何为您的应用程序建模。如果我需要像“init”这样的操作,我仍然会提出请求并将所有初始化代码放在商店中。也许我什至可以创建一个“InitializationStore”。
    • 另外,创建“做很多事情”的动作可能会增加动作真正含义的耦合。例如,像“登录”这样的动作,每秒调用 AJAX 的次数不应超过一次,但如果你有所有的 ajax 代码,那么你必须为动作保存一些状态,这样它就不会多次调用 ajax 直到第一个调用完成。如果您在商店中有 API 调用,它可以轻松处理此问题。此外,其他商店可能有兴趣知道用户请求登录,而不管 API 调用是否成功。
    • 是的。将后端访问权限放入商店是很有意义的。另见:stackoverflow.com/a/28101529/1775026
    【解决方案2】:

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

    那里描述的简短版本是:

    1. 不要使用 PreEmit 钩子

    2. 使用异步操作

    var MyActions = Reflux.createActions({
      "doThis" : { asyncResult: true },
      "doThat" : { asyncResult: true }
    });
    

    这不仅会创建“makeRequest”动作,还会创建“doThis.completed”、“doThat.completed”、“doThis.failed”和“doThat.failed”动作。

    1. (可选,但首选)使用 Promise 调用操作
    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);
      });
    

    我们最近重写了我们所有的操作和“preEmit”钩子到这个模式,并喜欢结果和生成的代码。

    【讨论】:

      【解决方案3】:

      我还发现异步与回流有点令人困惑。使用来自 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 模式也不是很感兴趣,所以我只使用 store 上的处理程序:

      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 回调,我可以接受。更容易理解我如何将回调数据设置到存储中。仍然保持单向。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多