Created
December 2, 2019 07:29
-
-
Save SPavelV/f6a5506e7aacb1bde35c5c17e63f29c9 to your computer and use it in GitHub Desktop.
React component ResizeObserver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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