From b8e7542c34fe4b773d7fc4aabbe319c4fae2dbef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=BD=E9=BE=99?= Date: Thu, 22 Jul 2021 16:09:44 +0800 Subject: [PATCH] fix: useSize error ResizeObserver loop limit exceeded --- packages/hooks/src/useSize/index.ts | 8 +++++--- packages/hooks/src/useSize/useRafState.ts | 24 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 packages/hooks/src/useSize/useRafState.ts diff --git a/packages/hooks/src/useSize/index.ts b/packages/hooks/src/useSize/index.ts index 375b91e772..2efd2b4605 100644 --- a/packages/hooks/src/useSize/index.ts +++ b/packages/hooks/src/useSize/index.ts @@ -1,11 +1,13 @@ -import { useState, useLayoutEffect } from 'react'; +import { useLayoutEffect } from 'react'; import ResizeObserver from 'resize-observer-polyfill'; -import { getTargetElement, BasicTarget } from '../utils/dom'; +import type { BasicTarget } from '../utils/dom'; +import { getTargetElement } from '../utils/dom'; +import useRafState from './useRafState'; type Size = { width?: number; height?: number }; function useSize(target: BasicTarget): Size { - const [state, setState] = useState(() => { + const [state, setState] = useRafState(() => { const el = getTargetElement(target); return { width: ((el || {}) as HTMLElement).clientWidth, diff --git a/packages/hooks/src/useSize/useRafState.ts b/packages/hooks/src/useSize/useRafState.ts new file mode 100644 index 0000000000..694595b8c0 --- /dev/null +++ b/packages/hooks/src/useSize/useRafState.ts @@ -0,0 +1,24 @@ +import type { Dispatch, SetStateAction } from 'react'; +import { useCallback, useRef, useState } from 'react'; +import useUnmount from '../useUnmount'; + +const useRafState = (initialState: S | (() => S)): [S, Dispatch>] => { + const frame = useRef(0); + const [state, setState] = useState(initialState); + + const setRafState = useCallback((value: S | ((prevState: S) => S)) => { + cancelAnimationFrame(frame.current); + + frame.current = requestAnimationFrame(() => { + setState(value); + }); + }, []); + + useUnmount(() => { + cancelAnimationFrame(frame.current); + }); + + return [state, setRafState]; +}; + +export default useRafState;