Skip to content

Instantly share code, notes, and snippets.

@blainekasten
Last active December 31, 2016 06:10
Show Gist options
  • Save blainekasten/20c1512c2d6fe87290f762395646ed2b to your computer and use it in GitHub Desktop.
Save blainekasten/20c1512c2d6fe87290f762395646ed2b to your computer and use it in GitHub Desktop.
Makes paths observable to state locations.
/*
* This is just a concept to use ES6 Proxies for a flux-like implementation where
* components are observers of state nodes. Using Proxie setters, when the specific
* state node is mutated, the components who observe that are re-rendered on the spot.
*
* likely missing some logic, just a concept
*/
import state from 'state';
import { componentToStateMap, pathMapper } from 'pathMapperProxy';
function observe(getProperties) {
const proxy = new Proxy(state, pathMapper);
const properties = getProperties(proxy);
const fromState = {};
Reflect.ownKeys(properties).forEach(k => {
// get the actual value from the state
fromState[k] = state[r[k].getPath]; // not exactly right, but general idea.
// push the observing component into a WeakMap ideally where path
// correlates to components.
// when the state is mutated, it iterates over that paths components
// and calls .forceUpdate()
componentToStateMap[r[k].getPath].push(ObservingComponent);
});
// functional-programming style
return (Component) => {
// a class so we get `.forceUpdate()`
// yes I realize this class is not in scope for the above `.push`, it's just an example
return class ObservingComponent extends React.Component {
render() {
return <Component {...props} {...fromState} />;
}
}
}
}
// Public API
observe(s => ({
foo: s.foo.bar,
baz: s.foo.baz[2],
}))(MyComponent)
// proxy does things like this:
// state.foo.bar => ".foo.bar"
let path = '';
export const componentToStateMap = {}; // should be a WeakMap
export const pathMapper = {
// this getter is the fancy way of building a path as you read
get(obj, reqNode) {
if (reqNode === 'getPath') {
let pathCopy = path;
path = ''
return pathCopy;
}
let objNode = obj[reqNode];
if (Array.isArray(obj)) {
path += `[${reqNode}]`;
} else {
path += `.${reqNode}`;
}
if (typeof objNode !== 'object') {
const finalResults = {getPath: path};
path = '';
return finalResults;
}
return new Proxy(obj[reqNode], pathMapper);
},
// this is sort of the magic,
// when a value is set, we have also built the path along the way
// since the getter is triggered too.
// with the path we can use our map to iterate and call forceUpdate
set(node, value) {
node = value;
componentToStateMap[path].forEach(comp => comp.forceUpdate())
}
}
// example state
export default {
foo: {
bar: 'yeah',
baz: [
{ far: [1]},
1,
2
],
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment