fluxx
Version:
Terse application state management
101 lines (77 loc) • 2.81 kB
JavaScript
;
exports.__esModule = true;
exports.GlobalStore = GlobalStore;
exports.LocalStore = LocalStore;
exports.default = Store;
var storeId = 1;
var stores = exports.stores = {};
function GlobalStore(optionsOrInitialState, registerHandlers) {
return Store(optionsOrInitialState, registerHandlers, true);
}
function LocalStore(optionsOrInitialState, registerHandlers) {
return Store(optionsOrInitialState, registerHandlers);
}
function Store(optionsOrInitialState, registerHandlers, isGlobal) {
var _ref = registerHandlers ? {} : optionsOrInitialState;
var handlers = _ref.handlers;
var initialState = registerHandlers ? optionsOrInitialState : optionsOrInitialState.state;
var onHandlers = {};
var dispatching = false;
var callbacks = [];
var disposeCb = undefined;
var instance = {
state: initialState,
log: Store.log,
onDispose: function onDispose(cb) {
disposeCb = cb;return instance;
}
};
instance.id = storeId++;
stores[instance.id] = instance;
// on(action, callback) registration style
if (registerHandlers) {
var on = function on(action, fn) {
onHandlers[action] = fn;
};
registerHandlers(on);
}
instance._handleAction = function (action, payloads) {
if (dispatching) throw new Error('Cannot dispatch an Action in the middle of another Action\'s dispatch');
// Bail fast if this store isn't interested.
var handler = handlers ? handlers[action._id] : onHandlers[action._id];
if (!handler) return;
dispatching = true;
if (instance.log) {
var payload = payloads.length > 1 ? payloads : payloads[0];
console.log('%c' + action._name, 'color: #F51DE3', 'dispatched with payload ', payload);
}
var previousState = instance.state;
try {
instance.state = handlers ? handler.apply(null, [instance.state].concat(payloads)) : handler(instance.state, payloads[0]);
} finally {
if (instance.log) {
var storeKind = isGlobal ? 'global' : 'local';
console.log('%cNew ' + storeKind + ' state:', 'color: blue', instance.state);
}
dispatching = false;
}
if (previousState !== instance.state) callbacks.forEach(function (callback) {
return callback(instance.state);
});
};
instance.subscribe = function (callback) {
callbacks.push(callback);
if (instance.log) console.log('%cInitial state:', 'color: green', initialState);
return function unsubscribe() {
callbacks = callbacks.filter(function (_callback) {
return _callback !== callback;
});
// Global stores remain active forever, but not local stores
if (!isGlobal && callbacks.length === 0) {
delete stores[instance.id];
if (disposeCb) disposeCb();
}
};
};
return instance;
}