From a1648439021a45c781c2074489d7c6aaaa867406 Mon Sep 17 00:00:00 2001 From: streamich Date: Sun, 12 Jan 2020 17:11:35 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20improve=20implementation?= =?UTF-8?q?=20of=20useMeasure()=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: useMeasure() now defaults all values to -1, if they were not set and internal implementation heavily refactored. --- src/useMeasure.ts | 61 +++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/useMeasure.ts b/src/useMeasure.ts index 4622355f6a..29ac5ad8db 100644 --- a/src/useMeasure.ts +++ b/src/useMeasure.ts @@ -1,39 +1,48 @@ -import { useCallback, useState } from 'react'; +import { useState, useMemo } from 'react'; import ResizeObserver from 'resize-observer-polyfill'; +import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'; -export type ContentRect = Pick; +export type UseMeasureRect = Pick< + DOMRectReadOnly, + 'x' | 'y' | 'top' | 'left' | 'right' | 'bottom' | 'height' | 'width' +>; +export type UseMeasureRef = (element: HTMLElement) => void; +export type UseMeasureResult = [UseMeasureRef, UseMeasureRect]; -const useMeasure = (): [(instance: T) => void, ContentRect] => { - const [rect, set] = useState({ - x: 0, - y: 0, - width: 0, - height: 0, - top: 0, - left: 0, - bottom: 0, - right: 0, - }); +const defaultState: UseMeasureRect = { + x: -1, + y: -1, + width: -1, + height: -1, + top: -1, + left: -1, + bottom: -1, + right: -1, +}; + +const useMeasure = (): UseMeasureResult => { + const [element, ref] = useState(null); + const [rect, setRect] = useState(defaultState); - const [observer] = useState( + const observer = useMemo( () => new ResizeObserver(entries => { - const entry = entries[0]; - if (entry) { - set(entry.contentRect); + if (entries[0]) { + const { x, y, width, height, top, left, bottom, right } = entries[0].contentRect; + setRect({ x, y, width, height, top, left, bottom, right }); } - }) + }), + [] ); - const ref = useCallback( - node => { + useIsomorphicLayoutEffect(() => { + if (!element) return; + observer.observe(element); + return () => { observer.disconnect(); - if (node) { - observer.observe(node); - } - }, - [observer] - ); + }; + }, [element]); + return [ref, rect]; };