Flux: Initialize from asynchronous storage with interdependent stores - waitFor
async - The real solution to this problem would be to create a DAO/service to feed data into the store via actions.
import AppDispatcher from '../dispatcher/AppDispatcher';
import AppConstants from '../constants/AppConstants';
import SettingsStore from '../stores/SettingsStore';
import assign from 'object-assign';
import events from 'events';
var EventEmitter = events.EventEmitter;
var CHANGE_EVENT = 'CHANGE_EVENT';
var SomeStore = assign({}, EventEmitter.prototype, {
// Returns a random number in this range: [0, SettingsStore.getMaxSetting())
getRandomNumber: function() {
return Math.random() * SettingsStore.getMaxSetting();
},
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
dispatchToken: AppDispatcher.register(function(action) {
switch(action.actionType) {
case AppConstants.APP_INIT:
// This isn't really necessary in this instance
// but is useful if perhaps SettingsStore needs to init some stuff
AppDispatcher.waitFor([
SettingsStore.dispatchToken
]);
// Once the SettingsStore has all of the data loaded
// from persistent storage, update the processor
SettingsStore.getIsInitializedPromise()
.then(function() {
// Emit a change so the views will pick up the new values
// that will come from the settings being loaded
SomeStore.emitChange();
});
break;
// Respond to other actions here
// ...
default:
// no op
}
// No errors. Needed by promise in Dispatcher.
return true;
})
});
import AppDispatcher from '../dispatcher/AppDispatcher';
import AppConstants from '../constants/AppConstants';
import assign from 'object-assign';
import Promise from 'bluebird';
// Small deferred constructor from: https://github.com/petkaantonov/bluebird/blob/master/API.md#deferred-migration
function deferredPromise() {
var resolve, reject;
var promise = new Promise(function() {
resolve = arguments[0];
reject = arguments[1];
});
return {
resolve: resolve,
reject: reject,
promise: promise
};
}
import events from 'events';
var EventEmitter = events.EventEmitter;
var CHANGE_EVENT = 'CHANGE_EVENT';
var isInitializedDeferredPromise = deferredPromise();
var maxSetting = 5;
var SettingsStore = assign({}, EventEmitter.prototype, {
getIsInitializedPromise: function() {
return isSettingsInitializedDeferredPromise.promise;
},
getMaxSetting: function() {
return maxSetting;
},
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
dispatchToken: AppDispatcher.register(function(action) {
switch(action.actionType) {
case AppConstants.APP_INIT:
retrieveSettingsFromPersistantStorage()
.then(function() {
console.log('Settings Retrieved!');
isInitializedDeferredPromise.resolve(true);
SettingsStore.emitChange();
})
.catch(function(e) {
console.log('Error retrieving playground settings:', e);
isInitializedDeferredPromise.reject(e);
});
break;
case AppConstants.APP_SET_MAX_SETTING:
maxSetting = action.value;
savePersistently();
SettingsStore.emitChange();
break;
// Respond to other actions here
// ...
default:
// no op
}
// No errors. Needed by promise in Dispatcher.
return true;
})
});
function retrieveSettingsFromPersistantStorage() {
return new Promise(function (resolve, reject) {
// Pretend `localStorage` is asynchonous in this example
setTimeout(function() {
maxSetting = window.localStorage.getItem('maxSetting');
resolve(true);
}, 2000);
});
}
function savePersistently() {
window.localStorage.setItem('maxSetting', maxSetting);
}
import React from 'react';
import SomeStore from '../stores/SomeStore';
import AppActions from '../actions/AppActions';
function gatherSomeStoreState(props, state) {
return {
myRandomNumber: SomeStore.getRandomNumber()
};
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
SomeStore.addChangeListener(this._onSomeStoreChange.bind(this));
// Initialize the application
AppActions.init();
}
componentWillUnmount() {
SomeStore.removeChangeListener(this._onSomeStoreChange.bind(this));
}
render() {
return (
<div>{this.state.myRandomNumber}</div>
);
}
_onSomeStoreChange() {
this.setState(gatherSomeStoreState(this.props, this.state));
}
}