Skip to content

Commit

Permalink
Perform updates to all text elements in a single read/write pass to p…
Browse files Browse the repository at this point in the history
…revent O(N) interstitial rerenders
  • Loading branch information
Jeremy Ong committed Jan 5, 2018
1 parent 5b1a8d6 commit d322703
Showing 1 changed file with 38 additions and 17 deletions.
55 changes: 38 additions & 17 deletions lib/ReactFitText.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,39 @@ var ReactDOM = require('react-dom');
var ReactPropTypes = require('prop-types');
var createClass = require('create-react-class');

// Map from node to options
const nodes = new Map();

function updateElementStyle(element, options, width) {
element.style.fontSize = `${Math.min(Math.max(width / (options.compressor * 10), options.minFontSize), options.maxFontSize)}px`;
}

let updateQueued = false;

function onBodyResize() {
updateQueued = true;
const widths = [];
nodes.forEach((options, element) => {
widths.push(element.offsetWidth);
});
let i = 0;
nodes.forEach((options, element) => {
updateElementStyle(element, options, widths[i]);
i += 1;
});
}

window.addEventListener("resize", onBodyResize);
window.addEventListener("load", onBodyResize);

module.exports = createClass({
displayName: 'ReactFitText',

propTypes: {
children: ReactPropTypes.element.isRequired,
compressor: ReactPropTypes.number,
minFontSize: ReactPropTypes.number,
maxFontSize: ReactPropTypes.number
maxFontSize: ReactPropTypes.number,
},

getDefaultProps: function() {
Expand All @@ -32,35 +57,31 @@ module.exports = createClass({
};
},

componentDidMount: function() {
window.addEventListener("resize", this._onBodyResize);
window.addEventListener("load", this._onBodyResize);
this._onBodyResize();
componentWillMount: function() {
if (!updateQueued) {
window.requestAnimationFrame(onBodyResize);
}
},

componentWillUnmount: function() {
window.removeEventListener("resize", this._onBodyResize);
window.removeEventListener("load", this._onBodyResize);
if (this._childRef) {
nodes.delete(this._childRef);
}
},

componentDidUpdate: function() {
this._onBodyResize();
onBodyResize();
},

_onBodyResize: function() {
var element = ReactDOM.findDOMNode(this);
var width = element.offsetWidth;
element.style.fontSize = Math.max(
Math.min((width / (this.props.compressor*10)),
parseFloat(this.props.maxFontSize)),
parseFloat(this.props.minFontSize)) + 'px';
},
_renderChildren: function(){
var _this = this;

return React.Children.map(this.props.children, function (child) {
return React.cloneElement(child, { ref: function ref(c) {
return _this._childRef = c;
if (c) {
nodes.set(c, _this.props);
}
_this._childRef = c;
} });
});
},
Expand Down

0 comments on commit d322703

Please sign in to comment.