MadLittleMods
5/7/2015 - 6:44 AM

Flux: Initialize from asynchronous storage with interdependent stores - `waitFor` async - The real solution to this problem would be to crea

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));
	}
}