Last active
May 16, 2016 09:29
-
-
Save yelouafi/9a6302d90adec6e54dc14797c9af9ace to your computer and use it in GitHub Desktop.
Observable state tree
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Redux basic example</title> | |
<script src="https://npmcdn.com/redux@latest/dist/redux.min.js"></script> | |
<script src="redux-dirty.js" charset="utf-8"></script> | |
</head> | |
<body> | |
<script> | |
const field = (name, seed) => (state=seed, action) => { | |
if(action.type === 'SET_FIELD' && action.field === name) | |
return action.value | |
return state | |
} | |
const store = createObservableStore(Redux.createStore)(combineWithObs({ | |
name: field('name', 'yassine'), | |
age: field('age', 38), | |
address: { | |
street: field('street', 'Rue Massinet'), | |
city: field('city', 'tanger') | |
} | |
})) | |
</script> | |
</body> | |
</html> |
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 remove(array, item) { | |
const index = array.indexOf(item) | |
if(index >= 0) { | |
array.splice(index, 1) | |
} | |
} | |
function emitter() { | |
const subscribers = [] | |
let dirty | |
let state | |
let initialized | |
function subscribe(sub) { | |
subscribers.push(sub) | |
return () => remove(subscribers, sub) | |
} | |
function notify() { | |
if(!dirty) return | |
for (var i = 0, len = subscribers.length; i < len; i++) { | |
subscribers[i](state) | |
} | |
dirty = false | |
} | |
function setState(newState) { | |
if(!initialized) { | |
initialized = true | |
state = newState | |
} else if(state !== newState) { | |
state = newState | |
dirty = true | |
} | |
} | |
return { | |
subscribe, | |
notify, | |
getState: () => state, | |
setState | |
} | |
} | |
function makeObs(reducer, key) { | |
const em = emitter() | |
function obsReducer(state, action) { | |
em.setState( reducer(state, action) ) | |
return em.getState() | |
} | |
obsReducer.name = em.name = key | |
obsReducer.emitter = em | |
return obsReducer | |
} | |
function combineWithObs(obj, key) { | |
const keys = Object.keys(obj) | |
const em = emitter() | |
em.$$children = [] | |
const childReducers = {} | |
keys.forEach(key => { | |
const ch = obj[key] | |
const chRed = typeof ch === 'function' ? makeObs(ch, key) : combineWithObs(ch, key) | |
childReducers[key] = chRed | |
em[key] = chRed.emitter | |
em.$$children.push(chRed.emitter) | |
}) | |
function combinedObs(state, action) { | |
let newState = state === undefined ? {} : undefined | |
for (var i = 0, len = keys.length; i < len; i++) { | |
updateChildState(keys[i], action) | |
} | |
if(!newState) { | |
return state | |
} else { | |
for (var i = 0, len = keys.length; i < len; i++) { | |
const key = keys[i] | |
if(!newState.hasOwnProperty(key)) { | |
newState[key] = state[key] | |
} | |
} | |
em.setState(newState) | |
return newState | |
} | |
function updateChildState(key, action) { | |
const oldChState = state !== undefined ? state[key] : undefined | |
const newChState = childReducers[key](oldChState, action) | |
if(state === undefined || oldChState !== newChState) { | |
if(!newState) newState = {} | |
newState[key] = newChState | |
} | |
} | |
} | |
combinedObs.emitter = em | |
return combinedObs | |
} | |
function createObservableStore(next) { | |
let rootEmitter | |
return function createStoreWithObs(reducer, initialState) { | |
const store = next(reducer, initialState) | |
rootEmitter = reducer.emitter | |
if(!rootEmitter) { | |
return store | |
} else { | |
return Object.assign({}, store, { | |
$: rootEmitter, | |
dispatch(action) { | |
const res = store.dispatch(action) | |
notify(rootEmitter) | |
return res | |
} | |
}) | |
} | |
} | |
function notify(em) { | |
em.notify() | |
const children = em.$$children | |
if(children) { | |
for (var i = 0, len = children.length; i < len; i++) { | |
notify(children[i]) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment