Skip to content

Instantly share code, notes, and snippets.

@SPavelV
Created December 2, 2019 07:29
Show Gist options
  • Select an option

  • Save SPavelV/f6a5506e7aacb1bde35c5c17e63f29c9 to your computer and use it in GitHub Desktop.

Select an option

Save SPavelV/f6a5506e7aacb1bde35c5c17e63f29c9 to your computer and use it in GitHub Desktop.
React component ResizeObserver
import React from "react";
// Extra extra large screen / large desktop
export const XXL = 1600;
// Extra large screen / full hd
export const XL = 1200;
// Large screen / wide desktop
export const LG = 1024;
// Medium screen / desktop
export const MD = 768;
// Small screen / tablet
export const SM = 640;
// Xtra small screen / mobile
export const XS = 480;
export enum SizeType {
XXL = "xxl",
XL = "xl",
LG = "lg",
MD = "md",
SM = "sm",
XS = "xs"
}
export interface ResizeObserverProps {
/**
* Событие при изменении размеров элемента
*
* @memberof ResizeObserverProps
*/
onResize?: () => void;
/**
* Событие при изменении типа ширины элемента
*
* @memberof ResizeObserverProps
*/
onChangeWidth?: (width: SizeType) => void;
/**
* Задержка в (ms) между перерисовками
*
* @type {number}
* @memberof ResizeObserverProps
*/
debounce?: number;
/**
* Оповещать размеры окна браузера вместо родительского контейнера
*/
windowCalculation?: boolean;
}
/**
* ResizeObserver component
*
* @export
* @class ResizeObserver
* @extends {React.Component<ResizeObserverProps>}
*/
export class ResizeObserver extends React.Component<ResizeObserverProps> {
private refContainer: HTMLDivElement | null;
private width: SizeType | null;
private observer: MutationObserver;
private timeout: number;
constructor(props: ResizeObserverProps) {
super(props);
}
componentDidMount() {
if (this.refContainer != null) {
this.onResize();
this.observer = new MutationObserver(this.onResize);
this.observer.observe(document.body, {
attributes: true,
subtree: true
});
window.addEventListener("resize", this.onResize);
}
}
componentWillUnmount() {
this.refContainer = null;
this.observer.disconnect();
this.timeout = 0;
window.removeEventListener("resize", this.onResize);
}
render() {
return (
<div ref={(ref) => this.refContainer = ref} className="resize-observer"/>
);
}
onResize = () => {
if (this.props.onResize) {
this.debounceResize();
}
const width = this.props.windowCalculation
? window.innerWidth
: this.refContainer
? this.refContainer.offsetWidth
: undefined;
if (width) {
const currentWidth = this.checkSize(width);
if (this.width !== currentWidth) {
this.width = currentWidth;
if (this.props.onChangeWidth) {
this.props.onChangeWidth(currentWidth);
}
}
}
};
debounceResize = () => {
window.clearTimeout(this.timeout);
const later = () => {
if (this.props.onResize) {
this.props.onResize();
}
};
const wait = this.props.debounce || 10;
this.timeout = window.setTimeout(later, wait);
};
checkSize = (width: number = 0): SizeType => {
if (width >= XXL) {
return SizeType.XXL;
}
if (width >= XL) {
return SizeType.XL;
}
if (width >= LG) {
return SizeType.LG;
}
if (width >= MD) {
return SizeType.MD;
}
if (width >= SM) {
return SizeType.SM;
}
return SizeType.XS;
};
}
export default ResizeObserver;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment