alistair
Version:
160 lines (149 loc) • 5.5 kB
TypeScript
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 };