Skip to content

Instantly share code, notes, and snippets.

@milankinen
Last active November 3, 2015 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milankinen/285d53026812d2834c87 to your computer and use it in GitHub Desktop.
Save milankinen/285d53026812d2834c87 to your computer and use it in GitHub Desktop.
React VDOM(Bacon.Observable) => Bacon.Observable(VDOM)
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