Last active
November 3, 2015 10:34
-
-
Save milankinen/285d53026812d2834c87 to your computer and use it in GitHub Desktop.
React VDOM(Bacon.Observable) => Bacon.Observable(VDOM)
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
import Bacon from "baconjs" | |
import React from "react" | |
import {cloneAndReplaceProps, isValidElement} from "react/lib/ReactElement" | |
import {find, isEmpty} from "lodash" | |
/** | |
* Transforms: VDOM(Observable) => Observable(VDOM) | |
* Example: | |
* const a = Bacon.constant(4) | |
* const b = Bacon.constant(3) | |
* const c = Bacon.combineWith(a, b, (a, b) => a + b) | |
* | |
* liftVDOM(<div>{a} + {b} = <span className="result">{c}</span></div>) | |
*/ | |
export default function liftVDOM(vdom) { | |
const obs = resolveObservables(vdom, []) | |
if (isEmpty(obs)) { | |
return Bacon.constant(vdom) | |
} else { | |
return Bacon | |
.combineAsArray(obs) | |
.map(values => assignObservableValues(vdom, values)) | |
} | |
function resolveObservables(el, obs) { | |
const propKeys = Object.keys(el.props || {}) | |
for (let k = 0 ; k < propKeys.length ; k++) { | |
const key = propKeys[k] | |
const prop = el.props[key] | |
if (key === "children") { | |
const children = prop | |
for (let i = 0 ; i < children.length ; i++) { | |
const child = children[i] | |
if (child instanceof Bacon.Observable && !find(obs, o => o.obs === child)) { | |
obs.push(child.map(value => ({obs: child, value}))) | |
} else if (isValidElement(child)) { | |
resolveObservables(child, obs) | |
} | |
} | |
} else { | |
if (prop instanceof Bacon.Observable && !find(obs, o => o.obs === prop)) { | |
obs.push(prop.map(value => ({obs: prop, value}))) | |
} | |
} | |
} | |
return obs | |
} | |
function assignObservableValues(el, obsValues) { | |
const newProps = {} | |
const propKeys = Object.keys(el.props || {}) | |
for (let k = 0 ; k < propKeys.length ; k++) { | |
const key = propKeys[k] | |
const prop = el.props[key] | |
if (key === "children") { | |
const children = prop | |
const newChildren = [] | |
for (let i = 0 ; i < children.length ; i++) { | |
const child = children[i] | |
if (child instanceof Bacon.Observable) { | |
newChildren.push(find(obsValues, r => r.obs === child).value) | |
} else if (isValidElement(child)) { | |
newChildren.push(assignObservableValues(child, obsValues)) | |
} else { | |
newChildren.push(child) | |
} | |
} | |
newProps.children = newChildren | |
} else { | |
if (prop instanceof Bacon.Observable) { | |
newProps[key] = find(obsValues, r => r.obs === prop).value | |
} else { | |
newProps[key] = prop | |
} | |
} | |
} | |
return cloneAndReplaceProps(el, newProps) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment