Created
May 12, 2015 09:52
-
-
Save rpominov/9e09a7c1228e813a40ef to your computer and use it in GitHub Desktop.
Another 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
const flux = createFlux(); | |
flux.addStore('counter', { | |
initial() { | |
return 0; | |
}, | |
reducers: { | |
add(cur, x) { | |
return cur + x; | |
}, | |
subtract(cur, x) { | |
return cur - x; | |
} | |
} | |
}); | |
// We can create several stores listening to same events. | |
flux.addStore('counterReverce', { | |
initial() { | |
return 0; | |
}, | |
reducers: { | |
add(cur, x) { | |
return cur - x; | |
}, | |
subtract(cur, x) { | |
return cur + x; | |
} | |
} | |
}); | |
// Action names don't have to be the same as events types they produce. | |
flux.addAction('plus', (flux, x) => { | |
flux.dispatch('add', x); | |
}); | |
flux.addAction('minus', (flux, x) => { | |
flux.dispatch('subtract', x); | |
}); |
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
const flux = createFlux(); | |
flux.addStore('scrollTop', { | |
initial() { | |
return null; | |
}, | |
reducers: { | |
updateScrollTop(_, next) { | |
return next; | |
} | |
} | |
}); | |
flux.addAction('watchScroll', (flux) => { | |
const update = () => { | |
flux.dispatch('updateScrollTop', document.body.scrollTop); | |
} | |
update(); | |
document.addEventListener('scroll', update); | |
flux.subscribeToDispose(() => document.removeEventListener('scroll', update)); | |
}); | |
flux.subscribe('scrollTop', (prev) => console.log('Scroll updated ', prev, '->', flux.state.scrollTop)); | |
flux.actions.watchScroll(); | |
// later... | |
flux.dispose(); | |
flux = null; |
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
const flux = createFlux(); | |
flux.addStore('todos', { | |
initial() { | |
return []; | |
}, | |
// Reducers must be pure functions! The method names are event types, | |
// they are share single namespace per flux instance. | |
reducers: { | |
todoAdd(items, text) { | |
return items.concat([ {text, completed: false, id: createId()} ]); | |
}, | |
todoRemove(items, id) { | |
return items.filter(item => item.id !== id); | |
}, | |
todoUpdateText(items, {id, text}) { | |
return items.map(item => item.id === id ? {id, text, completed: item.completed} : item); | |
}, | |
todoComplete(items, id) { | |
return items.map(item => item.id === id ? {id, text: item.text, completed: true} : item); | |
} | |
} | |
}); | |
// Same name for the action and the event it produces is coincidental. | |
flux.addAction('todoAdd', (flux, text) => { | |
// In an action you are allowed to read `flux.state`, but should avoid that. | |
// In an action you can dispatch any number of events, | |
// synchronously or asynchronously. | |
flux.dispatch('todoAdd', text); | |
}); | |
console.log("Initial 'todos' state", flux.state.todos); // [] | |
const unsubscribe = flux.subscribe('todos', (prevState) => { | |
console.log("State of 'todos' have changed from", prevState, "to", flux.state.todos); | |
}); | |
flux.actions.todoAdd('Implement Flux'); | |
// > State of 'todos' have changed from [] to [{"text":"Implement Flux","completed":false,"id":42}] | |
// We should have create an action for this... | |
flux.dispatch('todoComplete', 42); | |
// > State of 'todos' have changed from [{"text":"Implement Flux","completed":false,"id":42}] to | |
// ... [{"id":42,"text":"Implement Flux","completed":true}] | |
// Supposed to return unique IDs | |
function createId() { | |
return 42; | |
} |
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
function createFlux() { | |
let reducers = {}; | |
let currentlyDispatching = null; | |
let onChange = {}; | |
let onDispose = []; | |
let flux = { | |
state: {}, | |
actions: {}, | |
addStore(name, store) { | |
flux.state[name] = store.initial(); | |
Object.keys(store.reducers).forEach(type => { | |
reducers[type] = reducers[type] || []; | |
reducers[type].push({name, reducers: store.reducers}); | |
}); | |
}, | |
addAction(name, fn) { | |
flux.actions[name] = (...args) => { | |
return fn(flux, ...args); | |
}; | |
}, | |
dispatch(type, payload) { | |
if (currentlyDispatching === null) { | |
currentlyDispatching = type; | |
if (reducers[type]) { | |
reducers[type].forEach(({name, reducers}) => { | |
const prevState = flux.state[name]; | |
flux.state[name] = reducers[type](prevState, payload); | |
if (flux.state[name] !== prevState && onChange[name]) { | |
onChange[name].forEach(callback => callback(prevState)); | |
} | |
}); | |
} | |
currentlyDispatching = null; | |
} else { | |
throw new Error(`Can't dispatch event '${type}' because currently dispatching another event '${currentlyDispatching}'`); | |
} | |
}, | |
subscribe(name, callback) { | |
onChange[name] = onChange[name] ? onChange[name].concat([callback]) : [callback]; | |
return () => { | |
onChange[name] = removeFirst(onChange[name], callback); | |
}; | |
}, | |
subscribeToDispose(callback) { | |
onDispose = onDispose.concat(callback); | |
return () => { | |
onDispose = removeFirst(onDispose, callback); | |
}; | |
}, | |
dispose() { | |
onDispose.forEach(callback => callback()); | |
flux.state = flux.actions = reducers = onChange = onDispose = null; | |
} | |
}; | |
return flux; | |
} | |
function removeFirst(array, item) { | |
let met = false; | |
return array.filter(_item => met || _item !== item || (met = true, false)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Instead of:
it probably should be: