import React, { useCallback, useEffect, useInsertionEffect, useRef, useState } from 'react'; export function useMounted() { const mountedRef = useRef(false); const isMounted = useCallback(() => mountedRef.current, []); useEffect(() => { mountedRef.current = true; return () => { mountedRef.current = false; }; }, []); return isMounted; } export function useStyledRef(): React.RefObject { return useRef(null); } export function useCombinedRefs(...refs: (React.Ref | undefined)[]): React.RefCallback { return useRefCallback((element: T | null) => refs.forEach((ref) => assignToRef(element, ref))); } export function assignToRef(element: T | null, ref?: React.Ref) { if (typeof ref === 'function') { ref(element); } else if (ref && element) { (ref as React.RefObject).current = element; } } export function useBoolean(initialValue = false) { const [value, setValue] = useState(initialValue); const setTrue = useCallback(() => setValue(true), []); const setFalse = useCallback(() => setValue(false), []); const toggle = useCallback(() => setValue((value) => !value), []); return [value, setTrue, setFalse, toggle] as const; } // This hook returns a function that can be used to force a rerender of a component, and // additionally also returns a variable that can be used to trigger effects as a result. This is a // hack and should be avoided unless there are no better ways. export function useRerenderer(): [() => void, number] { const [count, setCount] = useState(0); const rerender = useCallback(() => setCount((count) => count + 1), []); return [rerender, count]; } type Fn = (...args: T) => R; export function useEffectEvent( fn: Fn>, ): Fn { const ref = useRef>(fn); useInsertionEffect(() => { ref.current = fn; }, [fn]); return useCallback((...args: Args) => ref.current(...args), []); } // Alias for useEffectEvent, but with another name since the effect event is named after a very // specific usecase. export const useRefCallback = useEffectEvent; export function useLastDefinedValue(value: T): T { const [definedValue, setDefinedValue] = useState(value); useEffect(() => setDefinedValue((prev) => value ?? prev), [value]); return value ?? definedValue; }