diff --git a/packages/ui/src/components/Modal.tsx b/packages/ui/src/components/Modal.tsx index 6320465a..48cd2972 100644 --- a/packages/ui/src/components/Modal.tsx +++ b/packages/ui/src/components/Modal.tsx @@ -2,7 +2,13 @@ import styled from "@emotion/styled"; import type { ComponentProps, MutableRefObject, ReactNode } from "react"; -import React, { Fragment, useEffect, useLayoutEffect, useRef } from "react"; +import React, { + Fragment, + useEffect, + useLayoutEffect, + useRef, + useState, +} from "react"; import ReactDOM from "react-dom"; import { useLiveRef } from "../hooks/useLiveRef.js"; import { Breakpoints, bp, useBreakpoints } from "../styles/breakpoints.js"; @@ -133,6 +139,7 @@ export function Modal({ topLeftIcon, }: ModalProps) { const visibleChangedRef = useRef(false); + const [visibleChanged, setVisibleChanged] = useState(false); const nodeRef = useRef(null); const [defaultFirstFocusRef, defaultFirstFocusRefCb] = useLiveRef(); const ref = firstFocusRef || defaultFirstFocusRef; @@ -146,9 +153,15 @@ export function Modal({ useEffect(() => { if (visible !== visibleChangedRef.current) { visibleChangedRef.current = visible; + setVisibleChanged(true); } }, [visible]); - const visibleChanged = visible !== visibleChangedRef.current; + + useEffect(() => { + if (visibleChanged) { + setVisibleChanged(false); + } + }, [visibleChanged]); useEffect(() => { prevFocusedElement.current = document.activeElement; diff --git a/packages/ui/src/hooks/useLiveRef.tsx b/packages/ui/src/hooks/useLiveRef.tsx index 15b38b62..125c6702 100644 --- a/packages/ui/src/hooks/useLiveRef.tsx +++ b/packages/ui/src/hooks/useLiveRef.tsx @@ -1,12 +1,10 @@ -import type { MutableRefObject, RefCallback } from "react"; -import { useCallback, useRef, useState } from "react"; +import { useCallback, useMemo, useRef, useState } from "react"; + +const defaultRef = { current: null }; /* For use when you need a rerender when the ref is actually assigned. Usually ref assignment does not trigger rerenders. */ -export function useLiveRef(): [ - MutableRefObject, - RefCallback, -] { +export function useLiveRef() { const [ready, setReady] = useState(false); const ref = useRef(null); const refCb = useCallback((node: T | null) => { @@ -16,5 +14,10 @@ export function useLiveRef(): [ } }, []); - return [ready ? ref : { current: null }, refCb]; + const value = useMemo( + () => [ready ? ref : defaultRef, refCb] as const, + [ready, ref, refCb], + ); + + return value; }