UNPKG

react-with-dimension

Version:

Debounced React high order component to expose container width and height.

119 lines (101 loc) 2.95 kB
import React, { Component } from 'react' import wrapDisplayName from 'recompose/wrapDisplayName' import debounce from 'lodash.debounce' const defaultGetHeight = (elem = {}) => { if (elem && elem.clientHeight) { return elem.clientHeight } if (elem && elem.getBoundingClientRect) { return elem.getBoundingClientRect().height } return undefined } const defaultGetWidth = (elem = {}) => { if (elem && elem.clientWidth) { return elem.clientWidth } if (elem && elem.getBoundingClientRect) { return elem.getBoundingClientRect().width } return undefined } const defaultTransform = (width, height) => ({ containerWidth: width, containerHeight: height }) const defaultContainerStyle = { width: '100%', height: '100%', padding: 0, border: 0, } const defaultDebounceOptions = { leading: false, trailing: true, maxWait: 800, } const withDimension = ({ transform = defaultTransform, containerStyle = defaultContainerStyle, getHeight = defaultGetHeight, getWidth = defaultGetWidth, wait = 200, debounceOptions = defaultDebounceOptions, } = {}) => (BaseComponent) => class extends Component { static displayName = wrapDisplayName(BaseComponent, 'withDimension') state = { containerWidth: null, containerHeight: null, } componentDidMount() { if (typeof window !== 'undefined' && window !== null && window.addEventListener) { this.canUpdate = true this.debouncedUpdate = debounce(this.updateDimensions, wait, debounceOptions) window.addEventListener('resize', this.debouncedUpdate, { passive: true }) this.debouncedUpdate() } } componentDidUpdate() { if (this.debouncedUpdate) { this.debouncedUpdate() } } componentWillUnmount() { if (typeof window !== 'undefined' && window !== null && window.removeEventListener) { this.canUpdate = false window.removeEventListener('resize', this.debouncedUpdate, { passive: true }) } } update = (elem) => { this.setState({ containerWidth: getWidth(elem), containerHeight: getHeight(elem), }) } updateDimensions = () => { const elem = this.withDimensionContainer if (!this.canUpdate) { return } if (this.state.containerWidth === getWidth(elem) && this.state.containerHeight === getHeight(elem) ) { return } if (typeof window !== 'undefined' && window !== null && window.requestAnimationFrame) { window.requestAnimationFrame(() => this.update(elem)) } else { this.update(elem) } } updateWithDimensionContainerRef = (node) => { this.withDimensionContainer = node } render() { return ( <div ref={this.updateWithDimensionContainerRef} style={containerStyle} > <BaseComponent {...transform(this.state.containerWidth, this.state.containerHeight)} {...this.props} /> </div> ) } } export default withDimension