Skip to content

Instantly share code, notes, and snippets.

@AprilArcus
Last active November 11, 2015 21:47
Show Gist options
  • Save AprilArcus/ef68b520134e57c42285 to your computer and use it in GitHub Desktop.
Save AprilArcus/ef68b520134e57c42285 to your computer and use it in GitHub Desktop.
import { default as React, Component, Children, cloneElement } from 'react';
class ComponentWithComputedWidths extends Component {
constructor(props) {
super(props);
this.state = { computedWidthsAvailable = false; computedWidths: {} };
this.updateComputedWidths = this.updateComputedWidths.bind(this);
}
updateComputedWidths() {
const { computedWidths } = this.state;
const updatedWidths = {};
let computedWidthsValid = true;
for (let key in refs) {
updatedWidths[key] = getComputedStyle(this.refs[key]).width;
if ( state.computedWidths[key] !== updatedWidths[key]) {
computedWidthsValid = false;
}
}
// if any of our children's computed widths have changed...
if (!computedWidthsValid) {
// set state, imperatively forcing a redraw
this.setState({
computedWidthsAvailable: true,
computedWidths: updatedWidths
});
}
// poll for changes at 60fps
requestAnimationFrame(this.updateComputedWidths);
}
componentDidMount() {
this.updateComputedWidths();
}
renderChildrenWithRefs(children) {
// uniquely label each component in the tree, depth first
let i = 0; // wide scope
return Children.map(children, function recur(child) {
if (typeof child === 'string') return child;
return cloneElement(
child,
{ refs: String(i++) }, // side effect!
Children.map(children, recur)
);
});
}
renderChildrenWithComputedWidths(children, computedWidths) {
const childrenWithRefs = this.renderChildrenWithRefs(children);
return Children.map(childrenWithRefs, function recur(child) {
if (typeof child === 'string') return child;
// now I want to do something with the retrieved style, by using
// the string value of ref to key into my store of computed styles
const width = computedWidths[child.props.ref]);
// but if typeof child.props.ref === 'function', I can't use it
// as a key!
return cloneElement(
child,
{ style: {...child.props.style, doSomeMathOn(width) },
Children.map(child.props.children, recur)
);
});
}
render() {
const { children } = this.props;
const { computedWidthsAvailable, computedWidths } = this.state;
return (
<div style={this.props.style} ref="container">
{ computedWidthsAvailable ?
this.renderChildrenWithRefs(children) :
this.renderChildrenWithComputedWidths(children, computedWidths);
}
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment