alistair
Version:
127 lines (124 loc) • 4.69 kB
text/typescript
import { Dispatch, SetStateAction, DependencyList } from 'react';
interface Atom<out T, in out W> {
/**
* Gets a value from the atom
* @returns The current value of the atom
*/
get: () => T;
/**
* The setter function for the atom
*/
set: Dispatch<W>;
/**
* Subscribes to the atom, and fires a callback when the atom changes
* @param notify A callback that will be fired when the atom changes, passes the new value
* @returns A function to unsubscribe from the atom
*/
subscribe: (notify: (value: T) => void) => () => void;
}
declare function atom<T>(initialValue?: T): Atom<T, SetStateAction<T>>;
/**
* Creates an atom with a writable interface. This is a more of an advanced API, and should only be reached for
* if you need logic that is more complex than what `atom` provides.
* @param init A value to initialize the atom with
* @param toAction A function that takes the next value and returns the next state or a function that takes the previous state and returns the next state
* @returns An atom with a writable interface
*
* @example
* ```ts
* function atomWithUpdatedAt<T>(initialValue: T) {
* // First generic is the value when read, second is the value to be set
* return writable<{value: T; updatedAt: number}, T>(
* // Initial value:
* {value: initialValue, updatedAt: Date.now()},
*
* // Calculate the next state
* next => ({value: next, updatedAt: Date.now()}),
* );
* }
*
* const atom = atomWithUpdatedAt(0);
*
* atom.get(); // {value: 0, updatedAt: <timestamp>}
*
* ```
*
* You can even take this a futher and write a reducer pattern, since the reducer has to return a `SetStateAction` (allowing you to access previous state).
*
* ```ts
* type Action = {type: 'increment'} | {type: 'decrement'} | {type: 'set'; value: number};
*
* function reducer(state: number, action: Action): number {
* switch (action.type) {
* case 'increment':
* return state + 1;
* case 'decrement':
* return state - 1;
* case 'set':
* return action.value;
* }
* }
*
* // Must pass `<number, Action>` type arguments
* const atom = writable<number, Action>(0, next => old => reducer(old, next));
*
* atom.set({type: 'increment'});
* atom.get(); // 1
*
* atom.set({type: 'set', value: 5});
* atom.get(); // 5
*
* atom.set({type: 'decrement'});
* atom.get(); // 4
* ```
*/
declare function writable<T, W = T>(init: T, toAction: (value: W) => SetStateAction<T>): Atom<T, W>;
/**
* Hook to get the current value of an atom
* @param atom The atom to consume
* @returns The current value of the atom
*/
declare function useAtomValue<T, W>(atom: Atom<T, W>): T;
/**
* Use the value of an atom
* @param atom The atom to consume
* @returns The current state of the atom, as well as a stable writer
*/
declare function useAtom<T, W>(atom: Atom<T, W>): [value: T, write: Dispatch<W>];
/**
* Get immediately notified when an atom's value changes
* @param atom The atom to listen to
* @param callback A callback that will be fired when the atom changes.
*/
declare function useAtomDidChange<T, W>(atom: Atom<T, W>, callback: (value: T) => void): void;
/**
* Selects/computes a value from an atom, and re-renders the component when the selected value changes
*
* The selector function can be unstable, but the value it returns should be stable. This means you could do something like this
* `const totalMessages = useSelectAtomValue(chatAtom, chat => chat.messages.length);`
*
* Or this is also okay, because you're not computing a new value, just selecting a value from the atom:
* `const message = useSelectAtomValue(chatAtom, chat => chat.messages);`
*
* But NOT this, because we make a new array every time the selector is called (which will trigger a re-render):
* `const totalMessages = useSelectAtomValue(chatAtom, chat => [...chat.messages, "hello"]);`
*
* If you need this kind of behaviour, you should use this in combination with `useMemo`:
*
* ```ts
* const messages = useSelectAtomValue(chatAtom, chat => chat.messages);
* const mappedMessages = useMemo(() => [...messages, "hello"], [messages]);
* ```
*
* @param atom The atom to select a value from-inherited from the atom
* @param selector The selector function
* @returns The selected value
*
* @example
* ```ts
* const messages = useSelectAtomValue(chatAtom, chat => chat.messages);
* console.log('messages', messages);
* ```
*/
declare function useSelectAtomValue<T, W, U>(atom: Atom<T, W>, selector: (atom: T) => U, dependencies?: DependencyList): U;
export { type Atom, atom, useAtom, useAtomDidChange, useAtomValue, useSelectAtomValue, writable };