From 0df9a02415c8ecf04a3fcac09ff4db6f30143baf Mon Sep 17 00:00:00 2001 From: Chance Strickland Date: Mon, 22 Jun 2020 07:40:47 -0700 Subject: [PATCH 1/2] rect: fix over-rendering and needless attachment of listeners --- packages/rect/src/index.tsx | 49 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/packages/rect/src/index.tsx b/packages/rect/src/index.tsx index 8464cd676..5be0e407c 100644 --- a/packages/rect/src/index.tsx +++ b/packages/rect/src/index.tsx @@ -91,43 +91,52 @@ export function useRect( observe: boolean = true, onChange?: (rect: DOMRect) => void ): null | DOMRect { + let [element, setElement] = useState(nodeRef.current); let initialRectSet = useRef(false); let [rect, setRect] = useState(null); - let observerRef = useRef(null); + let onChangeRef = useRef(); + useIsomorphicLayoutEffect(() => { - const cleanup = () => { - observerRef.current && observerRef.current.unobserve(); - }; + onChangeRef.current = onChange; + }); - if (!nodeRef.current) { - console.warn("You need to place the ref"); - return cleanup; + useIsomorphicLayoutEffect(() => { + if (nodeRef.current !== element) { + setElement(nodeRef.current); } + }); - if (!observerRef.current) { - observerRef.current = observeRect(nodeRef.current, (rect: DOMRect) => { - onChange && onChange(rect); - setRect(rect); - }); + useIsomorphicLayoutEffect(() => { + if (element && !initialRectSet.current) { + initialRectSet.current = true; + setRect(element.getBoundingClientRect()); } + }, [element]); - if (!initialRectSet.current) { - initialRectSet.current = true; - setRect(nodeRef.current.getBoundingClientRect()); + useIsomorphicLayoutEffect(() => { + if (!element) { + console.warn("You need to place the ref"); + return cleanup; } - observe && observerRef.current.observe(); + let observer = observeRect(element, (rect) => { + onChangeRef.current && onChangeRef.current(rect); + setRect(rect); + }); + + observe && observer.observe(); return cleanup; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [observe, onChange]); + + function cleanup() { + observer.unobserve(); + } + }, [observe, element]); return rect; } export default Rect; -export type PartialRect = Partial; - export type PRect = Partial & { readonly bottom: number; readonly height: number; From a3ca034b3539f3739566cb5753c37431c382dfbf Mon Sep 17 00:00:00 2001 From: Chance Strickland Date: Mon, 22 Jun 2020 14:23:36 -0700 Subject: [PATCH 2/2] rect: update deps + broaden types --- .../examples/change-observed-ref.example.tsx | 29 +++++++++++++++++++ packages/rect/package.json | 2 +- packages/rect/src/index.tsx | 14 +++++---- yarn.lock | 8 ++--- 4 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 packages/rect/examples/change-observed-ref.example.tsx diff --git a/packages/rect/examples/change-observed-ref.example.tsx b/packages/rect/examples/change-observed-ref.example.tsx new file mode 100644 index 000000000..ba50d93d0 --- /dev/null +++ b/packages/rect/examples/change-observed-ref.example.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { useRect } from "@reach/rect"; + +let name = "Change the observed ref"; + +function Example() { + const refLeft = React.useRef(null); + const refRight = React.useRef(null); + const [whichRect, setWhichRect] = React.useState(true); + const rect = useRect(whichRect ? refLeft : refRight); + return ( +
+
+        {whichRect ? "left" : "right"}: {JSON.stringify(rect, null, 2)}
+      
+ +
+