alt
Version:
A flux implementation
113 lines (92 loc) • 2.88 kB
JavaScript
import * as fn from '../functions'
import transmitter from 'transmitter'
class AltStore {
constructor(alt, model, state, StoreModel) {
const lifecycleEvents = model.lifecycleEvents
this.transmitter = transmitter()
this.lifecycle = (event, x) => {
if (lifecycleEvents[event]) lifecycleEvents[event].publish(x)
}
this.state = state
this.alt = alt
this.preventDefault = false
this.displayName = model.displayName
this.boundListeners = model.boundListeners
this.StoreModel = StoreModel
this.reduce = model.reduce || (x => x)
this.subscriptions = []
const output = model.output || (x => x)
this.emitChange = () => this.transmitter.publish(output(this.state))
const handleDispatch = (f, payload) => {
try {
return f()
} catch (e) {
if (model.handlesOwnErrors) {
this.lifecycle('error', {
error: e,
payload,
state: this.state,
})
return false
}
throw e
}
}
fn.assign(this, model.publicMethods)
// Register dispatcher
this.dispatchToken = alt.dispatcher.register((payload) => {
this.preventDefault = false
this.lifecycle('beforeEach', {
payload,
state: this.state,
})
const actionHandlers = model.actionListeners[payload.action]
if (actionHandlers || model.otherwise) {
let result
if (actionHandlers) {
result = handleDispatch(() => {
return actionHandlers.filter(Boolean).every((handler) => {
return handler.call(model, payload.data, payload.action) !== false
})
}, payload)
} else {
result = handleDispatch(() => {
return model.otherwise(payload.data, payload.action)
}, payload)
}
if (result !== false && !this.preventDefault) this.emitChange()
}
if (model.reduce) {
handleDispatch(() => {
const value = model.reduce(this.state, payload)
if (value !== undefined) this.state = value
}, payload)
if (!this.preventDefault) this.emitChange()
}
this.lifecycle('afterEach', {
payload,
state: this.state,
})
})
this.lifecycle('init')
}
listen(cb) {
if (!fn.isFunction(cb)) throw new TypeError('listen expects a function')
const { dispose } = this.transmitter.subscribe(cb)
this.subscriptions.push({ cb, dispose })
return () => {
this.lifecycle('unlisten')
dispose()
}
}
unlisten(cb) {
this.lifecycle('unlisten')
this.subscriptions
.filter(subscription => subscription.cb === cb)
.forEach(subscription => subscription.dispose())
}
getState() {
return this.StoreModel.config.getState.call(this, this.state)
}
}
export default AltStore