import { useDebounce, useUpdateEffect } from 'react-use'; import { Dispatch, SetStateAction, useState, useCallback } from 'react'; type UseStateType = typeof useState; type UseDebouncedStateReturn = [ T, Dispatch>, T, () => boolean | null ]; export type UseDebouncedStateType = (initialValue: T, ms: number, useStateHook?: UseStateType) => UseDebouncedStateReturn; export const useDebouncedState = (initialValue: T, ms: number, useStateHook?: UseStateType): UseDebouncedStateReturn => { if (!useStateHook) { useStateHook = useState; } const [ debouncedState, setDebouncedState ] = useStateHook(initialValue); const [ state, setState ] = useState(debouncedState); const debounceCallback = useCallback(() => { if (state !== debouncedState) { setDebouncedState(state); } }, [ state, setDebouncedState, debouncedState ]); useUpdateEffect(() => { setState(debouncedState); }, [ debouncedState ]); const [ isReady ] = useDebounce(debounceCallback, ms, [ state ]); return [ state, setState, debouncedState, isReady ]; };