Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/446.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何进行正确的异步调用_Javascript_Asynchronous_Reactjs_React Jsx_Refluxjs - Fatal编程技术网

Javascript 如何进行正确的异步调用

Javascript 如何进行正确的异步调用,javascript,asynchronous,reactjs,react-jsx,refluxjs,Javascript,Asynchronous,Reactjs,React Jsx,Refluxjs,我最近开始学习ReactJS,但我对异步调用感到困惑 假设我有一个带有用户/通行证字段和登录按钮的登录页面。组件看起来像: var Login = React.createClass({ getInitialState: function() { return { isLoggedIn: AuthStore.isLoggedIn() }; }, onLoginChange: function(loginState

我最近开始学习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>
        );
    }
});
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

我的问题是我做得对吗

我是否应该使用action preEmit并执行以下操作:

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

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

问题在于抢占,因为它使对组件的回调更加复杂。我想学习正确的方法,并找到使用ReactJS/ReflewStack放置后端调用的位置。

我还发现async与ReflewStack有点混淆。利用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
      });
  }
});

我不喜欢在商店里做这件事,但是考虑到reflux是如何将动作抽象出来的,并且会一直启动listenTo回调,我对它没意见。更容易解释如何将回拨数据设置到存储中。仍然保持它的单向性。

我也在使用回流,我对异步调用使用了不同的方法

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

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


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

对于回流,您应该仔细查看

上面描述的内容的简短版本是:

  • 不要使用PreEmit挂钩

  • 不要使用异步操作

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

  • (可选,但首选)使用承诺来调用操作

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

    感谢您的回答。您如何看待这种方法
    actions.init.listen
    ?因为我做了一项研究,很多人都是按你的方式做的,但也有很多人是按实际行动做的。所以我很困惑,无法决定使用哪种模式。人们使用它的方式存在差异,因为对于反流,没有“正确的方式”。这实际上取决于你想如何为你的应用程序建模。如果我需要像‘init’这样的操作,我仍然会发出请求,并将所有init代码放在一个存储中。也许我甚至可以创建一个“InitializationStore”。此外,创建“做很多事情”的操作可能会增加对操作真正含义的耦合。例如,具有AJAX调用的“login”之类的操作不应每秒调用一次以上,但如果您的所有AJAX代码都在其中,则必须为该操作保存一些状态,以便在第一次调用完成之前,不会多次调用AJAX。如果你在商店里有API调用,它可以很容易地处理这个问题。另外,其他商店可能有兴趣知道用户请求登录,而不管API call.Yup是否成功。将后端访问权放到商店中才有意义。另见:
    var MyActions = Reflux.createActions({
      "doThis" : { asyncResult: true },
      "doThat" : { asyncResult: true }
    });
    
    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);
      });