Skip to content

Instantly share code, notes, and snippets.

@undoZen
Created October 20, 2016 08:22
Show Gist options
  • Save undoZen/b6695e370fdcaa1612d2501e0accf194 to your computer and use it in GitHub Desktop.
Save undoZen/b6695e370fdcaa1612d2501e0accf194 to your computer and use it in GitHub Desktop.
an failed experiment with freezer-js
'use strict'
import Freezer from 'freezer-js'
import {assign, isArray, each, toPath} from 'lodash'
import h from 'react-hyperscript'
import {Component, PureComponent} from 'react'
var store = new Freezer({})
export default store
console.log(store);
export function getNameSpaceAndLastRef(data, p) {
var ps = toPath(p)
var lpk = ps.pop()
return [ps.reduce(function(result, pk, idx) {
if (!(pk in result)) {
return result.set(pk, {})[pk]
} else {
return result[pk]
}
}, data), lpk]
}
export function getState(p, d) {
return getFrom(store.get(), p, d)
}
console.log(getState());
export function getFrom(data, p, d) {
if (!p) return data
var [ns, lpk] = getNameSpaceAndLastRef(data, p)
return lpk in ns || typeof d === 'undefined'
? ns[lpk]
: ns.set(lpk, d)[lpk]
}
export function setState(p, v) {
return setTo(store.get(), p, v)
}
export function setTo(data, p, v) {
var [ns, lpk] = getNameSpaceAndLastRef(data, p)
return ns.set(lpk, v)[lpk]
}
export function resetState(p, v) {
return resetTo(store.get(), p, v)
}
export function resetTo(data, p, v) {
var [ns, lpk] = getNameSpaceAndLastRef(data, p)
if (!(lpk in ns)) {
return ns.set(lpk, v)[lpk]
}
return ns[lpk].reset(v)
}
export var eventHub = store.getEventHub()
export class StoreHOC extends Component {
}
var actions = {}
var updates = {}
export function setStore ({actions, updates}) {
}
console.log('store loaded')
export function commit(id, getData, commit, update, payload) {
var process = (allUpdates[id] || {})[update]
var data = getData()
var get = (p, d) => getFrom(getData(), p, d)
var set = (p, v) => p ? setTo(getData(), p, v) : getData().set(v)
var reset = (p, v) => p ? resetTo(getData(), p, v) : getData().reset(v)
console.log('commit', data, arguments);
if (typeof process !== 'function') {
return get()
}
process({payload, get, set, reset, commit})
return getData()
}
export function dispatch(id, getData, dispatch, parentDispatch, commit, action, payload) {
console.log('dispatch', arguments);
var process = (allActions[id] || {})[action]
var data = getData()
var get = (p, d) => getFrom(getData(), p, d)
var set = (p, v) => p ? setTo(getData(), p, v) : getData().set(v)
var reset = (p, v) => p ? resetTo(getData(), p, v) : getData().reset(v)
const parent = typeof parentDispatch === 'function'
? parentDispatch.bind(null, action, payload)
: () => Promise.resolve(null)
if (typeof process !== 'function') {
return parent()
}
return Promise.resolve(process({payload, get, set, reset, dispatch, commit, parent}).then(() => null))
}
const allActions = {}
const allUpdates = {}
export function StoreComponent(id, {actions, updates}) {
allActions[id] = actions || {}
allUpdates[id] = updates || {}
return {
react: reactHOC(id)
}
}
function reactHOC(id) {
return function getReactHOC(viewComponent) {
return class extends PureComponent {
constructor (props) {
super(props)
console.log(props)
if (!props.data) {
throw new Error('props.data required!')
}
this.dataIsNode = props.data && props.data.__
this.store = new Freezer(this.dataIsNode ? {wrapped: props.data} : props.data)
this.getData = () => this.dataIsNode ? this.store.get().wrapped : this.store.get()
this.state = {
data: this.commit('init')
}
this.dispatch('init')
}
commit = (update, payload) => commit(id, this.getData, this.commit, update, payload)
dispatch = (action, payload) => dispatch(id, this.getData, this.dispatch, this.props.dispatch, this.commit, action, payload)
componentWillReceiveProps (nextProps) {
const {data} = nextProps
const current = this.getData()
if (this.state.data !== current) {
this.setState({
data: current
})
}
if (data === current) {
return
}
if (this.dataIsNode) {
const root = this.store.get()
if (!data.__ || !data.__.parents) {
console.log(1, data, root, current);
root.set('wrapped', data)
this.dispatch('reset', [])
return
}
if (!data.__.parents.length || data.__.parents.indexOf(root) < 0) {
console.log(2, data, root, current);
root.set('wrapped', data)
this.dispatch('reset', [])
return
} else {
// will eventually trigger updata
return
}
}
const changed = Object.keys(data).filter(
pk => data[pk] !== current[pk]
)
if (changed.length) {
console.log(changed);
const newData = changed.reduce(
(state, pk) => {
if (state[pk] && state[pk].__) {
state[pk].reset(data[pk])
} else {
state.set(pk, data[pk])
}
return this.getData()
},
this.getData()
)
this.dispatch('reset', changed)
}
}
componentDidMount () {
console.log('did mount');
this.updateListener = (function updateListener(newData, oldData) {
if (newData !== oldData) {
this.setState({
data: this.dataIsNode ? newData.wrapped : newData
})
}
}.bind(this))
this.store.on('update', this.updateListener)
}
componentWillUnmount () {
console.log('will unmount');
this.store.off('update', this.updateListener)
const data = this.store.get()
this.store = null
data.remove(Object.keys(data))
//this.setState({data: null})
}
render() {
return h(viewComponent, {
...this.props,
dispatch: this.dispatch,
commit: this.commit,
data: this.state.data,
get: (p) => getFrom(this.getData(), p)
})
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment