Skip to content

Instantly share code, notes, and snippets.

@alkhe
Last active August 29, 2015 14:24
Show Gist options
  • Save alkhe/baf9ca571038ccdc22e8 to your computer and use it in GitHub Desktop.
Save alkhe/baf9ca571038ccdc22e8 to your computer and use it in GitHub Desktop.
fluxette
import React from 'react';
import Store from './store';
import { deriveState, normalizeArray, callAll, callAllObj, listenerKey } from './util';
export { Store };
export default class {
constructor(stores = {}) {
// Top-level Stores
this.stores = stores;
// Dispatcher
this.hooks = new Set();
// Action Stack
this.history = [];
}
state() {
return deriveState(this.stores);
}
dispatch(...data) {
// Normalize array of actions
data = normalizeArray(data);
// Push all actions onto stack
this.history.push(...data);
let { stores } = this;
// Synchronously process all actions
callAllObj(stores, data);
// Call all registered listeners
callAll(this.hooks, deriveState(stores));
}
hook(fn) {
// Add listener
this.hooks.add(fn);
}
unhook(fn) {
// Remove listener
this.hooks.delete(fn);
}
connect(specifier) {
// decorator for React class
let { hooks } = this;
let state = ::this.state;
return (Component) =>
class extends React.Component {
constructor(...args) {
super(...args);
// Initial state
this.state = state();
// Ensure the same reference of setState
this[listenerKey] = ::this.setState;
// Register setState
hooks.add(this[listenerKey]);
}
componentWillUnmount(...args) {
super.componentWillUnmount(...args);
// Unregister setState
hooks.delete(this[listenerKey]);
}
render() {
let { props, state } = this;
// Proxy props and state, but call the specifier on the state if provided
return <Component { ...props } { ...(specifier ? specifier(state) : state) } />;
}
}
}
}
export default function(state = {}, reducers = {}) {
// Function that takes an action or array of actions
return actions => {
// If no actions, just return state
if (actions !== undefined) {
// Ensure actions are an array
if (!(actions instanceof Array)) {
actions = [actions];
}
// Call the appropriate reducer with the state and the action
actions.forEach(action => {
let red = reducers[action.type];
if (red) {
state = red(state, action);
}
});
}
return state;
};
}
import _ from './lodash';
export let deriveState = stores => _.mapValues(stores, store => store());
export let normalizeArray = _.flattenDeep;
export let callAll = (iterable, ...data) => {
for (let fn of iterable) {
fn(...data);
}
};
export let callAllObj = (keyIterable, ...data) => {
for (let key in keyIterable) {
keyIterable[key](...data);
}
};
export let listenerKey = Symbol();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment