【问题标题】:Calling other action on the basis of results of other action in React JS根据 React JS 中其他操作的结果调用其他操作
【发布时间】:2015-02-23 12:24:38
【问题描述】:

我有一个 PageComponent 它包含以下反应组件:-

  1. 添加项目表单。 [表单组件]
  2. 项目的分页列表。 [用户列表组件]

当用户在“添加项目”表单中单击“添加项目”时。使用 ActionCreator 调用操作,然后它调用 API 服务器以及成功/失败回调。

//Calling action action creator from the component
ActionCreator.addUser({email:email, dept_code:dept});


//Action Creator calling action using dispatcher.
addUser: function(userObj){
  ApiClient.addUser(
    userObj,
    function(response){
       AppDispatcher.handleServerAction({actionType:ActionTypes.ADD_USER_SUCCESS, response: response});
    }.bind(this),
    function(error){
       AppDispatcher.handleServerAction({actionType:ActionTypes.ADD_USER_FAIL, error: error});
    }.bind(this)
  );
}

当调用成功/失败回调时,它会调度一个动作,例如 ADD_USERS_SUCCESS。

我已将 PageStore 配置为监听此操作并通知用户表单已提交。

  dispatcherIndex: AppDispatcher.register(function(payload) {
      var action = payload.action;
      switch(action.actionType){
         case ActionTypes.LOAD_USERS_SUCCESS:
            persistStoreData(false, null, action.usersObj);
            break;
         case ActionTypes.LOAD_USERS_FAIL:
            persistStoreData(false, payload.action.error, {});
            break;
         case ActionTypes.ADD_USER_SUCCESS:
            updateAddFormData(false, "Added", "success", []);
            break;
         case ActionTypes.ADD_USER_FAIL:
            updateAddFormData(true, "Add Failed! Click to retry..", "danger", payload.action.error);
            break;
         default:
            return true;
      }
      UsersStore.emitChange();
      return true; // No errors. Needed by promise in Flux Dispatcher.
 })

问题是如果触发了 ADD_USERS_SUCCESS 操作,我如何更新我的 UserListComponent。

我想到了以下解决方案:-

  1. 触发一个操作(例如 LOAD_USERS),如果我的状态中有一个像 {reloadUserTable: true} 这样的标志,它将在我的渲染方法上列出用户,例如?

  2. 在渲染方法中更新状态,但根据 Facebook 文档,在渲染方法中更新状态是 AntiPattern。

【问题讨论】:

    标签: reactjs reactjs-flux


    【解决方案1】:

    您可以在 PageComponent 内部维护状态,并使用 props 属性让它的“孩子”(UserListComponent)访问它。

    var PageComponent = React.createClass({
             getUserState: function() {
                return {
                    allUsers: UsersStore.getAllUsers()
                }
             },
             getInitialState: function() {
                return getUserState();
             },
             /* at ADD_USERS_SUCCESS */
             onChange: function() {
                this.setState(getUserState());
             },
             render: function() {
                <FormComponent />
                {/* inside UserListComponent, access all users using this.props.users */}
                <UserListComponent users={this.state.allUsers} />
             }});
    

    【讨论】:

    • 如果我可以提出建议,对您的代码所做的一些描述可能会对提问者有所帮助。
    • 在“onChange”事件中从视图调用存储是可以的,或者我应该调用如下操作:onChange: function() { ActionCreator.loadUsers({page:1}); ; },
    • 在商店更新自己以响应操作后,它们会发出更改事件。视图侦听更改事件,从存储中检索新数据。换句话说,从视图中调用 Store 完全没问题。无需在 onChange 上调用其他操作。
    • 谢谢,我明白你在说什么。我需要触发 Action 从 Web 服务器获取用户列表数据,因为我在某个地方读到了商店不应该直接与 Web 服务对话。
    • 是的,成功/失败的 Web 服务应该使用通过调度程序传递给商店的数据调用操作,然后商店可以使用新数据更新自己并发出更改。
    【解决方案2】:

    如果您的 PageStore 包含对链接到 UserListComponent 组件的页面的引用,那么在成功时您可以添加到该引用并发出更改。

    【讨论】:

    • 谢谢,问题是这种方法需要大量与客户端分页维护相关的工作。所以我想从服务器获取用户列表。
    • 如果您总是要加载用户(以及分页),那么为什么不触发 load 事件以及 ADD_USER_SUCCESS 事件呢?
    【解决方案3】:

    只需在子组件上公开一个方法供父组件调用 - http://facebook.github.io/react/tips/expose-component-functions.html

    【讨论】:

    • 请详细说明您的答案,不要简单地参考文档。该文档与问题有何关系?
    【解决方案4】:

    我解决此问题的工作解决方案如下所示。 @oppo 给出的解决方案中的 _onChange 回调帮助了我。

    我做了什么来解决这个问题:- 1. 调用添加用户操作时,我在商店中设置了一个标志,例如 {reloadUsers:true} 2. 查看组件的 _onChange 回调检查这个标志,如果它是真的,那么它会触发一个动作从 API 服务器加载数据。

    以下是商店

    'use strict';
    var AppDispatcher = require('../dispatcher/AppDispatcher');
    var Constants = require('../constants/Constants');
    var EventEmitter = require('events').EventEmitter;
    var assign = require('object-assign');
    
    var ActionTypes = Constants.ActionTypes;
    var CHANGE_EVENT = 'change';
    var _state = {
                   loading: false,
                   error : null,
                   users: {},
                   isAdded: true,
                   addFormErrors: [],
                   reloadUsers: false //Whether to reload user table or not
                };
    //Stores data recieved from server on page load
    function persistStoreData(loading, error, response) {
       _state.loading = loading;
       _state.error = error;
       _state.users = response;
       _state.reloadUsers = false;
    }
    
    //Updates data recieved from server if data saved
    function updateAddFormData(enableSave){
       _state.enableAddButton = enableSave;
       if(!_state.enableAddButton){
          _state.isAdded = true;
          _state.reloadUsers = true;
       }
       else{
          _state.isAdded = false;
       }
    }
    
    var UsersStore = assign({}, EventEmitter.prototype, {
       getState: function(){
          return _state;
       },
    
       getUsers: function(){
          return this._users;
       },
    
       emitChange: function() {
        //console.log('store change event');
        this.emit(CHANGE_EVENT);
       },
    
       /**
       * @param {function} callback
       */
      addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
      },
    
      /**
       * @param {function} callback
       */
      removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
      },
    
      dispatcherIndex: AppDispatcher.register(function(payload) {
          var action = payload.action;
          switch(action.actionType){
             case ActionTypes.LOAD_USERS_SUCCESS:
                persistStoreData(false, null, action.usersObj);
                break;
             case ActionTypes.LOAD_USERS_FAIL:
                persistStoreData(false, payload.action.error, {});
                break;
             case ActionTypes.ADD_USER_SUCCESS:
                updateAddFormData(false, "Added", "success", []);
                break;
             case ActionTypes.ADD_USER_FAIL:
                updateAddFormData(true, payload.action.error);
                break;
             default:
                return true;
          }
          UsersStore.emitChange();
          return true; // No errors. Needed by promise in Flux Dispatcher.
     })
    
    });
    module.exports = UsersStore;
    

    下面是调度器

    'use strict';
    var Constants = require('../constants/Constants');
    var Dispatcher = require('flux').Dispatcher;
    var assign = require('object-assign');
    
    var PayloadSources = Constants.PayloadSources;
    
    var AppDispatcher = assign(new Dispatcher(), {
    
      /**
       * @param {object} action The details of the action, including the action's
       * type and additional data coming from the server.
       */
      handleServerAction: function(action) {
        var payload = {
          source: PayloadSources.SERVER_ACTION,
          action: action
        };
        this.dispatch(payload);
      }
    
    });
    
    module.exports = AppDispatcher;
    

    以下是我的常量

    var keyMirror = require('keymirror');
    
    module.exports = {
       ActionTypes: keyMirror({
          ADD_USER_SUCCESS: null,
          ADD_USER_FAIL: null,
    
          LOAD_USERS: null,
          LOAD_USERS_SUCCESS: null,
          LOAD_USERS_FAIL: null,
       }),
       PayloadSources: keyMirror({
          SERVER_ACTION: null,
       })
    };
    

    下面是动作创建者

    'use strict';
    var AppDispatcher = require('../dispatcher/AppDispatcher');
    var Constants = require('../constants/Constants');
    var ApiClient = require('../clients/ApiClient');
    var ActionTypes = Constants.ActionTypes;
    
    var ActionCreator = {
    
      loadUsers: function(){
         ApiClient.getUsers(function(usersObj) {
           AppDispatcher.handleServerAction({actionType:ActionTypes.LOAD_USERS_SUCCESS, usersObj: usersObj});
         }.bind(this), function(error) {
          AppDispatcher.handleServerAction({actionType:ActionTypes.LOAD_USERS_FAIL, error: error});
         }.bind(this));
       }
    
        addUser: function(userObj){
          ApiClient.addUser(
            userObj,
            function(response){
               AppDispatcher.handleServerAction({actionType:ActionTypes.ADD_USER_SUCCESS, response: response});
            }.bind(this),
            function(error){
               AppDispatcher.handleServerAction({actionType:ActionTypes.ADD_USER_FAIL, error: error});
            }.bind(this)
          );
        }
    };
    module.exports = ActionCreator;
    

    以下是主要的视图组件(仅重要部分)

    'use strict';
    var React = require('react');
    var ActionCreator = require('../actions/ActionCreator');
    var UsersStore = require('../stores/UsersStore');
    var UsersTable = require('./UsersTable.jsx');
    var UserAddForm = require('./UserAddForm.jsx');
    var ManageUsers = React.createClass({
    
      getInitialState: function() {
          return UsersStore.getState();
      },
    
      componentDidMount: function() {
          ActionCreator.loadUsers();//Invoking Action, loading initial data
          UsersStore.addChangeListener(this._onChange);
      },
    
      componentWillUnmount: function() {
         UsersStore.removeChangeListener(this._onChange);
      },
    
      _onChange: function() {
         var state = UsersStore.getState();
         if(state.reloadUsers === true){
           //Only reload users if state has this variable set
           ActionCreator.loadUsers();
         }
         else{
           this.setState(state);
         }
      },
      render: function(){
        //Rendering logic would go here, below is just a prototype
        return (
           <div>
           <UserAddForm onSubmit={handleFormSubmit} />
           <UsersTable/>
           </div>
        );
      }
    });
    
    module.exports = ManageUsers;
    

    下面是API客户端

    'use strict';
    var $ = require('jquery');
    var ApiClient = {
    
       getUsers : function(success, failure){
          $.ajax({
             url : '/api/get-users',
             dataType: 'json',
             success : function(data){
                success(data);
             },
             error : function(jqXHR, textStatus, errorThrown){
                failure(errorThrown);
             }
          });
       },
    
       addUser : function(data, success, failure){
          $.ajax({
             url : '/api/add-user',
             dataType: 'json',
             type: 'post',
             data: 'data='+JSON.stringify(data),
             success : function(data){
                success(data);
             },
             error : function(jqXHR){
                var errorObj = {};
                try{
                  errorObj = JSON.parse(jqXHR.responseText);
                }
                catch(e){
                  errorObj['main'] = "An error occured";
                }
                failure(errorObj);
             }
          });
       }
    };
    module.exports = ApiClient;
    

    【讨论】:

      猜你喜欢
      • 2016-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多