Вызов другого действия на основе результатов другого действия в React JS
У меня есть PageComponent, он содержит следующие компоненты реакции:-
- Добавить форму товара. [FormComponent]
- Нумерация страниц. [UserListComponent]
Когда пользователь нажимает на Добавить элемент в форме добавления элемента. Действие вызывается с помощью ActionCreator, а затем оно вызывает сервер API вместе с обратным вызовом Success/Failure.
//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.
})
Проблема в том, как мне обновить свой UserListComponent, если запущено действие ADD_USERS_SUCCESS.
Я имею в виду следующее решение:
Вызываете ли вы действие (например, LoAD_USERS), которое будет перечислять пользователей в моем методе рендеринга, например, если у меня есть флаг в моем состоянии, например {reloadUserTable: true}?
Обновление состояния в методе рендеринга, но согласно состоянию обновления документов в Facebook в методе рендеринга - AntiPattern
4 ответа
Вы можете поддерживать состояния внутри PageComponent и разрешать его "детям" (UserListComponent) обращаться к нему с помощью свойства props.
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} />
}});
Если ваш PageStore содержит ссылку на страницы, связанные с компонентом UserListComponent, то в случае успеха вы можете добавить к этой ссылке и создать изменения.
Просто предоставьте метод дочернего компонента для вызова родительского компонента - http://facebook.github.io/react/tips/expose-component-functions.html
Мое рабочее решение для решения этой проблемы, как показано ниже. Обратный вызов _onChange в решении, заданном @oppo, помог мне.
Что я сделал, чтобы решить эту проблему:- 1. Когда вызывается добавление действия пользователя, я устанавливаю флаг в своем магазине, как {reloadUsers:true} 2. Просмотр проверки обратного вызова _onChange компонента для этого флага, если он равен true, тогда он вызывает действие для загрузки данных с сервера 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;