UNPKG

alistair

Version:
160 lines (149 loc) 5.5 kB
import { Dispatch, SetStateAction } from 'react'; type UseAsyncFunctionState<R> = { loading: boolean; result: { type: 'initial'; } | { type: 'success'; data: R; } | { type: 'error'; error: unknown; }; }; /** * Wraps an async function to provide state. Useful for mutations and form submissions. * Does NOT allow concurrent runs. You must wait for the previous run to finish before starting a new one. * * @param execute The async function to run and have state for * @returns The state of the last run, as well as a function to start new runs. The run function cannot be called if a previous run is in flight. The run function will return the result of the async function. * * @example * ```tsx * const [state, run] = useAsyncFunction(async (a: number, b: number) => { * const result = await addingApi.add(a, b); * return result; * }); * * return ( * <> * <button disabled={state.loading} onClick={() => run(1, 2)}>Run</button> * {state.loading && <p>Loading...</p>} * {state.type === 'success' && <p>Result: {state.data}</p>} * {state.type === 'error' && <p>Error: {JSON.stringify(state.error)}</p>} * </> * ) * ``` */ declare function useAsyncFunction<A extends unknown[], R>(execute: (...args: A) => Promise<R>): [ state: UseAsyncFunctionState<R>, run: (...args: A) => Promise<UseAsyncFunctionState<R>['result']>, reset: () => void ]; /** * Stabilise a function - useful to use as an event listener callback or similar * @param fn A function to completely stabilise * @returns A stable reference to the function, it will never change */ declare function useEvent<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R; /** * A completely reactive hook to run a function on an interval * @param callback A callback to run on a set interval * @param delay The interval between each tick */ declare function useInterval(callback: () => void, delay: number | null, options?: { runImmediately?: boolean; }): void; /** * Detects if the browser is currently online * @returns If the client is currently only. Returns false on the server */ declare function useIsOnline(): boolean; /** * A hook to detect if the current tab is focused or not * @returns A boolean if the current tab is focused */ declare function useIsTabFocused(): boolean; /** * @deprecated this has been renamed to `useIsTabFocused` */ declare const useTabFocused: typeof useIsTabFocused; /** * Creates a ref that can be initalized with a callback (lazily). * This is useful so we don't have to construct a class or call a function every time we * call this hook in a component as that could be costly. * * Inspiration is from https://github.com/facebook/react/issues/14490 * * @param init Initial value * @returns A React ref that was initalized with `init` * * @example * const ref = useLazyRef(() => new MyExpensiveClass()); * ref.current.doSomething(); */ declare function useLazyRef<T>(init: () => T): React.MutableRefObject<T>; /** * Use a value from local storage, with a setter. Will trigger updates wherever the same key is used around your app, and even works cross tab. * @param key The key to store data under * @param init An initialiser if the key does not already exist * @returns A tuple containing the value from local storage, synced across tabs, as well as a setter to update the value. * @example * ```tsx * import {useLocalStorage} from 'alistair/hooks'; * * function useCounter() { * return useLocalStorage('counter', () => 1); * } * * function Child() { * const [value] = useCounter(); * * // This will update no matter where it changes! * // This can include modifying it in dev tools, or changing it in another tab with the hook. * // It will **always** stay in sync * return <div>{value}</div>; * } * * function App() { * const [, set] = useCounter(); * * return ( * <> * <button onClick={() => set(old => old + 1)}>click</button> * <Child /> * <Child /> * </> * ); * } * ``` */ declare function useLocalStorage<T>(key: string, init: () => T): [value: T, set: Dispatch<SetStateAction<T>>]; /** * Throttle a value to be updated at a maximum of once per `limit` milliseconds. * @param value The value to throttle * @param limit Milliseconds to throttle by * @returns The value after it has been throttled * * @example * const [value, setValue] = useState(0); * // `throttledValue` will only change at a maximum of once per 1000ms * const throttledValue = useThrottle(value, 1000); */ declare function useThrottle<T>(value: T, limit?: number): T; interface ToggleControl { on: () => void; off: () => void; toggle: () => void; reset: () => void; } /** * Store a toggle boolean state with utility methods * @param initialState The initial state, optional * @returns A tuple containing the value and controls to update it * @example * const [isOpen, {toggle}] = useToggle(); * return <button onClick={toggle}>Toggle Something</button>; */ declare function useToggle(initialState?: boolean): [enabled: boolean, control: ToggleControl]; export { type ToggleControl, type UseAsyncFunctionState, useAsyncFunction, useEvent, useInterval, useIsOnline, useIsTabFocused, useLazyRef, useLocalStorage, useTabFocused, useThrottle, useToggle };