index.js |
|
import React, {Component} from 'react';
const BLOCKED = {};
export const globalOptions = {debug:false};
|
|
¶ deriveCreate a derived data higher-order component (HoC). Params
options
Object
(optional)
debug
Boolean
(optional)
Returns
Object
{Object}
|
export function derive(options={}) {
return DecoratedComponent => class DeriveDecorator extends Component {
static displayName = `Derive(${getDisplayName(DecoratedComponent)})`;
static DecoratedComponent = DecoratedComponent;
componentWillMount() {
this.derivedProps = deriveProps(options, {}, this.props, {});
}
componentWillUpdate(nextProps) {
this.derivedProps = deriveProps(options, this.props, nextProps, this.derivedProps || {});
}
render() {
return React.createElement(DecoratedComponent, this.derivedProps);
}
}
}
|
|
function deriveProps(options, prevProps, nextProps, derivedProps) {
const nextDerivedProps = {};
const calcDerivedProp = (key, xf) => {
|
When |
if (xf.trackedProps && xf.trackedProps.every(p => prevProps[p] === nextProps[p])) {
return derivedProps[key];
}
if (globalOptions.debug) console.log(`Recalculating derived prop '${key}'`);
return xf.call(delegates, nextProps, derivedProps);
};
|
|
const delegates =
options::map((xf,key) =>
() => {
if (!nextDerivedProps.hasOwnProperty(key)) {
nextDerivedProps[key] = BLOCKED;
return nextDerivedProps[key] = calcDerivedProp(key, xf);
} else {
if (nextDerivedProps[key] === BLOCKED) {
throw Error(`Circular dependencies in derived props, '${key}' was blocked.`)
}
return nextDerivedProps[key]
}
});
Object.keys(options).forEach(key => {
if (!nextDerivedProps.hasOwnProperty(key))
|
calculate derived prop |
nextDerivedProps[key] = calcDerivedProp(key, options[key]);
});
return {...nextProps, ...nextDerivedProps};
}
function getDisplayName (comp) {
return comp.displayName || comp.name || 'Component';
}
|
map an object to an object |
function map(f, result={}) {
Object.keys(this).forEach(k => result[k] = f(this[k],k));
return result;
}
|
¶ trackObject literal decorator that annotates a mapper function
to have a 'trackedProps' property. Used by Params
trackedProps
String...
Returns
Function
{Function}
|
export function track(...trackedProps) {
return function(target, key, descriptor) {
descriptor.value.trackedProps = trackedProps;
}
}
|
export class Derive extends Component {
componentWillMount() {
this.derivedProps = deriveProps(this.props.options, {}, this.props, {});
}
componentWillUpdate(nextProps) {
this.derivedProps = deriveProps(nextProps.options, this.props, nextProps, this.derivedProps || {});
}
render() {
return React.Children.only(this.props.children(this.derivedProps));
}
}
|