Ok, I guess the way you are implementing Flux does not seem to be the best one.
Let me share an example:
//ModelActions.js
export default class ModelActions {
static actionOne(params) {
Dispatcher.handleViewAction({
actionType: 'ACTION_ONE_STARTING'
});
fetch('uri', ...params)
.then(resp => {
Dispatcher.handleViewAction({
actionType: 'ACTION_ONE_SUCCESS',
payload: resp
});
//I could also dispatch more actions here, like:
Dispatcher.handleViewAction({
actionType: 'ACTION_TWO'
});
})
.catch((error) => {
Dispatcher.handleViewAction({
actionType: 'ACTION_ONE_ERROR',
payload: error.message
});
});
}
}
//ModelStore.js
import { EventEmitter } from 'events';
import assign from 'object-assign';
import YourDispatcher from '../dispatcher/YourDispatcher';
let ModelStore = assign({}, EventEmitter.prototype, {
emitChange() {
this.emit('change');
},
addChangeListener(callback) {
return this.on('change', callback);
},
removeChangeListener(callback) {
this.removeListener('change', callback);
},
actionOneStarting() {
return _isActionOneStarting;
},
actionOneSuccess() {
return _isActionOneSuccess;
},
getActionOneError() {
return _actionOneError;
},
getActionOnePayload() {
return _actionOnePayload;
}
});
ModelStore.dispatchToken = YourDispatcher.register((action) => {
switch (action.actionType) {
case 'ACTION_ONE_STARTING':
_isActionOneStarting = true;
_isActionOneSuccess = false;
ModelStore.emitChange();
break;
case 'ACTION_ONE_SUCCESS':
_isActionOneStarting = false;
_isActionOneSuccess = true;
_actionOnePayload = action.payload;
ModelStore.emitChange();
break;
case 'ACTION_ONE_ERROR':
_isActionOneStarting = false;
_isActionOneSuccess = false;
_actionOnePayload = null;
_actionOneError = action.error
ModelStore.emitChange();
break;
default:
break;
}
});
module.exports = ModelStore;
//YourComponent.js
import React, { Component } from 'react';
import ModelActions from '../../actions/ModelActions';
import ModelStore from '../../stores/ModelStore';
export default class YourComponent extends Component {
componentDidMount() {
ModelStore.addChangeListener(this._onStoreChange);
ModelActions.actionOne();
}
componentWillUnmount() {
ModelStore.removeChangeListener(this._onStoreChange);
}
render() {
return (
);
}
_onStoreChange() {
this.setState({
starting: ModelStore.actionOneStarting(),
success: ModelStore.actionOneSuccess(),
error: ModelStore.getActionOneError(),
payload: ModelStore.getActionOnePayload()
}, () => {
//Here the component will react as soon as an action arrives
//DOes not matter how many actions are dispatched
});
}
}
Summarizing, you can dispatch as many actions as you want, each store who get interested in such actions must then have a swith for catching that action, react to the change and emit the changes, the same applies for components, which must start listening all stores needed.
Now lets take a look at how using Redux it would look like:
//YourComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import ModelActions from '../actions/ModelActions';
export default class YourComponent extends Component {
componentDidMount() {
this.props.actionOne();
}
render() {
return (
//You dont need to change the state any more, just render based on props
);
}
}
const mapStateToProps = state => {
return {
starting: state.model.starting,
success: state.model.success,
error: state.model.error,
payload: state.model.payload,
}
}
const mapDispatchToProps = dispatch => {
return {
actionOne: () => ModelActions.actionOne()(dispatch) //There is a tiny trick here, look for [redux-thunk](https://github.com/gaearon/redux-thunk)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(YourComponent);
//ModelActions.js
export function ModelActions(params) {
return dispatch => {
dispatch({type: 'ACTION_ONE_STARTING'});
fetch('uri', ...params)
.then(resp => {
dispatch({type: 'ACTION_ONE_SUCCESS', payload: resp});
})
.catch((error) => {
dispatch({type: 'ACTION_ONE_ERROR', payload: error.message});
});
}
}
//model.js
const initialState = {
starting: false,
success: false,
error: null,
payload: null,
};
export default function model(state = initialState, action = {}) {
switch (action.type) {
case 'ACTION_ONE_STARTING':
return {
...state,
starting: true,
success: false
}
case 'ACTION_ONE_SUCCESS':
return {
...state,
starting: false,
success: true,
payload: action.payload
}
case 'ACTION_ONE_ERROR':
return {
starting: false,
success: false,
error: action.payload
}
default:
return state;
}
}
In redux, stores are replaced with reducers, components and actions are pretty similar. One of the main differences between pure Flux and redux, is that redux injects through props all information components need to render, ensuring that the entire state of the app lives on the reducers instead of living into the components.
You will find an excellent explanation about the differences between redux and pure Flux (I say pure Flux because redux is a sort un Flux implementation) here
For more information about redux, refer to the Official Site