mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 20:53:24 +10:00
Add lazyLoadWithDimensions HOC
This commit is contained in:
parent
f97cf4827a
commit
71d834bdd5
1 changed files with 106 additions and 0 deletions
|
|
@ -68,3 +68,109 @@ export const withViewport = Component => {
|
|||
|
||||
return WithViewportComponent;
|
||||
};
|
||||
|
||||
/**
|
||||
* A higher order component (HOC) that lazy loads the current element and provides
|
||||
* dimensions to the wrapped component as a `dimensions` prop that has
|
||||
* the shape `{ width: 600, height: 400}`.
|
||||
*
|
||||
* @param {React.Component} Component to be wrapped by this HOC
|
||||
* @param {Object} options pass in options like maxWidth and maxHeight.
|
||||
*
|
||||
* @return {Object} HOC component which knows its dimensions
|
||||
*/
|
||||
export const lazyLoadWithDimensions = (Component, options) => {
|
||||
// The resize event is flooded when the browser is resized. We'll
|
||||
// use a small timeout to throttle changing the viewport since it
|
||||
// will trigger rerendering.
|
||||
const THROTTLE_WAIT_MS = 200;
|
||||
// First render default wait after mounting (small wait for styled paint)
|
||||
const RENDER_WAIT_MS = 100;
|
||||
|
||||
class LazyLoadWithDimensionsComponent extends ReactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.element = null;
|
||||
this.defaultRenderTimeout = null;
|
||||
|
||||
this.state = { width: 0, height: 0 };
|
||||
|
||||
this.handleWindowResize = this.handleWindowResize.bind(this);
|
||||
this.isElementInViewport = this.isElementInViewport.bind(this);
|
||||
this.setDimensions = throttle(this.setDimensions.bind(this), THROTTLE_WAIT_MS);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('scroll', this.handleWindowResize);
|
||||
window.addEventListener('resize', this.handleWindowResize);
|
||||
window.addEventListener('orientationchange', this.handleWindowResize);
|
||||
|
||||
this.defaultRenderTimeout = window.setTimeout(() => {
|
||||
if (this.isElementInViewport()) {
|
||||
this.handleWindowResize();
|
||||
}
|
||||
}, RENDER_WAIT_MS);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('scroll', this.handleWindowResize);
|
||||
window.removeEventListener('resize', this.handleWindowResize);
|
||||
window.removeEventListener('orientationchange', this.handleWindowResize);
|
||||
window.clearTimeout(this.defaultRenderTimeout);
|
||||
}
|
||||
|
||||
handleWindowResize() {
|
||||
this.setDimensions();
|
||||
}
|
||||
|
||||
setDimensions() {
|
||||
this.setState(prevState => {
|
||||
const { clientWidth, clientHeight } = this.element || { clientWidth: 0, clientHeight: 0 };
|
||||
return { width: clientWidth, height: clientHeight };
|
||||
});
|
||||
}
|
||||
|
||||
isElementInViewport() {
|
||||
if (this.element) {
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
|
||||
return (
|
||||
rect.top >= 0 &&
|
||||
rect.left >= 0 &&
|
||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const dimensions = this.state;
|
||||
const { width, height } = dimensions;
|
||||
const props = { ...this.props, dimensions };
|
||||
|
||||
// lazyLoadWithDimensions HOC needs to take all given space
|
||||
// unless max dimensions are provided through options.
|
||||
const { maxWidth, maxHeight } = options;
|
||||
const maxWidthMaybe = maxWidth ? { maxWidth } : {};
|
||||
const maxHeightMaybe = maxHeight ? { maxHeight } : {};
|
||||
const style = { width: '100%', height: '100%', ...maxWidthMaybe, ...maxHeightMaybe };
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={element => {
|
||||
this.element = element;
|
||||
}}
|
||||
style={style}
|
||||
>
|
||||
{width !== 0 && height !== 0 ? <Component {...props} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoadWithDimensionsComponent.displayName = `lazyLoadWithDimensions(${Component.displayName ||
|
||||
Component.name})`;
|
||||
|
||||
return LazyLoadWithDimensionsComponent;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue