Created
June 29, 2014 22:23
-
-
Save spoike/ba561727a3f133b942dc to your computer and use it in GitHub Desktop.
A simpler implementation of React.JS's Flux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var EventEmitter = require('events').EventEmitter, | |
_ = require('lodash'); | |
/** | |
* Creates an action functor object | |
*/ | |
exports.createAction = function() { | |
var action = new EventEmitter(), | |
eventLabel = "action", | |
functor; | |
functor = function() { | |
action.emit(eventLabel, Array.prototype.slice.call(arguments, 0)); | |
}; | |
/** | |
* Subscribes the given callback for action triggered | |
* | |
* @param {Function} callback The callback to register as event handler | |
* @param {Mixed} [optional] bindContext The context to bind the callback with | |
* @returns {Function} Callback that unsubscribes the registered event handler | |
*/ | |
functor.listen = function(callback, bindContext) { | |
var eventHandler = function(args) { | |
callback.apply(bindContext, args); | |
}; | |
action.addListener(eventLabel, eventHandler); | |
return function() { | |
action.removeListener(eventLabel, eventHandler); | |
}; | |
}; | |
return functor; | |
}; | |
/** | |
* Creates an event emitting Data Store | |
* | |
* @param {Object} definition The data store object definition | |
*/ | |
exports.createStore = function(definition) { | |
var store = new EventEmitter(), | |
eventLabel = "change"; | |
function Store() { | |
if (this.init && _.isFunction(this.init)) { | |
this.init(); | |
} | |
} | |
_.assign(Store.prototype, definition); | |
Store.prototype.listenTo = function(listenable, callback) { | |
if (!_.isFunction(listenable.listen)) { | |
throw new TypeError(listenable + " is missing a listen method"); | |
} | |
return listenable.listen(callback, this); | |
}; | |
Store.prototype.listen = function(callback, bindContext) { | |
var eventHandler = function(args) { | |
callback.apply(bindContext, args); | |
}; | |
store.addListener(eventLabel, eventHandler); | |
return function() { | |
action.removeListener(eventLabel, eventHandler); | |
}; | |
}; | |
Store.prototype.trigger = function() { | |
var args = Array.prototype.slice.call(arguments, 0); | |
store.emit(eventLabel, args); | |
}; | |
return new Store(); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Reflux = require('./src/reflux'); | |
// Creating an Action | |
var textUpdate = Reflux.createAction(); | |
var statusUpdate = Reflux.createAction(); | |
// Creating a Data Store - Listening to textUpdate action | |
var textStore = Reflux.createStore({ | |
init: function() { | |
this.listenTo(textUpdate, this.output); | |
}, | |
output: function() { | |
var i, args = Array.prototype.slice.call(arguments, 0); | |
for (i = 0; i < args.length; i++) { | |
this.writeOut(args[i]); | |
} | |
}, | |
writeOut: function(text) { | |
this.trigger(text); | |
} | |
}); | |
// Creating a DataStore | |
var statusStore = Reflux.createStore({ | |
init: function() { | |
this.listenTo(statusUpdate, this.output); | |
}, | |
output: function(flag) { | |
var status = flag ? 'ONLINE' : 'OFFLINE'; | |
this.trigger(status); | |
} | |
}); | |
// Creating an aggregate DataStore that is listening to textStore and statusStore | |
var storyStore = Reflux.createStore({ | |
init: function() { | |
this.listenTo(statusStore, this.statusChanged); | |
this.listenTo(textStore, this.textUpdated); | |
this.storyArr = []; | |
}, | |
statusChanged: function(flag) { | |
if (flag === 'OFFLINE') { | |
this.trigger('Once upon a time the user did the following: ' + this.storyArr.join(', ')); | |
// empty storyArr | |
this.storyArr.splice(0, this.storyArr.length); | |
} | |
}, | |
textUpdated: function(text) { | |
this.storyArr.push(text); | |
} | |
}); | |
// Fairly simple view component that outputs to console | |
function ConsoleComponent() { | |
textStore.listen(function(text) { | |
console.log('text: ', text); | |
}); | |
statusStore.listen(function(status) { | |
console.log('status: ', status); | |
}); | |
storyStore.listen(function(story) { | |
console.log('story: ', story); | |
}); | |
}; | |
var consoleComponent = new ConsoleComponent(); | |
// Invoking the action with arbitrary parameters | |
statusUpdate(true); | |
textUpdate("testing", 1337, { "test": 1337 }); | |
statusUpdate(false); | |
/** Will output the following: | |
* | |
* status: ONLINE | |
* text: testing | |
* text: 1337 | |
* text: { test: 1337 } | |
* story: Once upon a time the user did the following: testing, 1337, [object Object] | |
* status: OFFLINE | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Find a typo in reflux.js (line 67):
action.removeListener(eventLabel, eventHandler);
should bestore.removeListener(eventLabel, eventHandler);