Skip to content

Instantly share code, notes, and snippets.

@ldayan
Forked from goatslacker/alt-stateless.js
Last active August 29, 2015 14:23
Show Gist options
  • Select an option

  • Save ldayan/c507765ab87a7a96080c to your computer and use it in GitHub Desktop.

Select an option

Save ldayan/c507765ab87a7a96080c to your computer and use it in GitHub Desktop.
import { Dispatcher } from 'flux'
function isPromise(obj) {
return obj && (typeof obj === 'object' || typeof obj === 'function') &&
typeof obj.then === 'function'
}
const inject = Math.random().toString(16).substr(2, 7)
class Alt {
constructor(options = {}) {
this.dispatcher = new options.Dispatcher()
this.serialize = options.serialize || JSON.stringify
this.deserialize = options.deserialize || JSON.parse
this.actions = {}
this.stores = {}
this.history = options.history || 2
this.payloads = []
this.state = this.serialize({})
}
createActions(namespace, model) {
this.actions[namespace] = Object.keys(model).reduce((actions, name) => {
const action = (...args) => {
const data = model[name](...args)
const meta = { namespace, name, args }
if (isPromise(data)) {
data
.then(x => this.dispatcher.dispatch({ action, data: x, meta }))
.catch(e => this.dispatcher.dispatch({ action: null, data: e, meta }))
} else {
this.dispatcher.dispatch({ action, data, meta })
}
}
actions[name] = action
return actions
}, {})
return this.actions[namespace]
}
createStore(namespace, reducer, initialState, ...args) {
const subscriptions = []
let state = initialState
this.payloads[namespace] = []
// save the state to app level state
const saveState = state => {
const appState = this.deserialize(this.state)
appState[namespace] = state
this.state = this.serialize(appState)
if (this.payloads.length - 1 < this.history) {
this.payloads[namespace].push(state)
}
}
// dispatch event
this.dispatcher.register((payload) => {
state = reducer(state, payload, ...args)
subscriptions.forEach(f => f(state))
})
// our store
const store = {
name: namespace,
subscribe: (onChange) => {
const id = subscriptions.push(onChange)
return () => subscriptions.splice(id, 1)
},
peek: (n = 1) => {
const payloads = this.payloads[namespace]
return payloads[payloads.length - n - 1]
},
[inject]: newState => saveState(state = newState)
}
// save the initial state
saveState(initialState)
// make it available
this.stores[namespace] = store
// listener to save state locally for history
store.subscribe(saveState)
return store
}
takeSnapshot() {
return this.state
}
bootstrap(serializedData) {
const data = this.deserialize(serializedData)
Object.keys(data).forEach((name) => {
this.stores[name][inject](data[name])
})
}
prepare(store, payload) {
return this.serialize({
[store.name]: payload
})
}
recycle() {
Object.keys(this.stores).forEach((name) => {
this.stores[name][inject](this.payloads[name][0])
})
}
flush() {
const snapshot = this.takeSnapshot()
this.recycle()
return snapshot
}
}
import assign from 'object-assign'
const alt = new Alt({ Dispatcher, history: 300 })
// The name is for
// A) to reference this later
// B) DispatcherRecorder and logging
const actions = alt.createActions('Actions', {
fire(x) {
return x
},
blah() { }
})
console.log('Actions =>', actions)
const store = alt.createStore('MyStore', (state, { action, data, meta }) => {
return assign({}, state, {
b: data
})
}, {
a: 0,
b: 0
})
console.log('Store =>', store)
console.log('Snapshot 1, 3', alt.takeSnapshot())
store.subscribe((state) => {
console.log('* Change Event:', state)
})
actions.fire(1)
actions.fire(2)
actions.fire(3)
actions.fire(4)
console.log('PEEKING 0, 1', store.peek(3))
const newState = store.peek(3) // 0, 1
const serialized = alt.prepare(store, newState) // MyStore: { a: 0, b: 1 }
alt.bootstrap(serialized)
console.log('Snapshot 0, 1', alt.takeSnapshot())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment