Custom Recoil atoms and hooks for basic application needs. All atoms are wrappers around native Recoil's atom
function,
so they enforce particular data structure depending on the atom type.
This library only includes static atoms for data storage, no asynchronous logic is involved.
npm i recoil-tools --save
or
yarn add recoil-tools
Useful for organizing and managing data in a list format.
Created using listAtom
.
// atoms/listState.ts
import { listAtom } from 'recoil-tools';
export default listAtom<
{ id: string; email: string },
{ activeItemId: string | null }
>({
key: 'listState',
default: {
data: [],
meta: { activeItemId: null },
},
});
Access to the list state and setters is provided through useRecoilList
hook.
import { useRecoilList } from 'recoil-tools';
import listState from './atoms/listState';
function App() {
const [state, setters] = useRecoilList(listState);
}
You can also use only state's data
property:
import { useRecoilListData } from 'recoil-tools';
import listState from './atoms/listState';
function App() {
const users = useRecoilListData(listState);
}
Or only meta
property:
import { useRecoilListMeta } from 'recoil-tools';
import listState from './atoms/listState';
function App() {
const { activeUserId } = useRecoilListMeta(listState);
}
Or only state setters:
import { useRecoilListSetters } from 'recoil-tools';
import listState from './atoms/listState';
function App() {
const { push, reverse } = useRecoilListSetters(listState);
}
type RecoilListState<T, U> = Readonly<{
/**
* Data items.
*/
data: T[];
/**
* Any metadata related to the list.
*/
meta: U;
}>;
type RecoilListSetters<T, U> = Readonly<{
/**
* `data` property setter.
*/
setData: SetterOrUpdater<T[]>;
/**
* Alias for `setData([])`.
*/
clearData: () => void;
/**
* `meta` property setter.
*/
setMeta: SetterOrUpdater<U>;
/**
* Inserts an arbitrary number of items at the start of the list.
*/
unshift: (...items: T[]) => void;
/**
* Inserts an arbitrary number of items at the end of the list.
*/
push: (...items: T[]) => void;
/**
* Clears list and inserts an arbitrary number of items.
* Basically a combination of `clearData` and `push`.
*/
clearPush: (...items: T[]) => void;
/**
* Inserts a new item if predicate doesn't return `true`.
*/
upsert: (predicate: (item: T, index: number) => boolean, newItem: T) => void;
/**
* Updates an item at a particular index.
*/
updateAt: (index: number, item: T) => void;
/**
* Updates first item satisfying predicate.
*/
update: (predicate: (item: T, index: number) => boolean, newItem: T) => void;
/**
* Updates all items satisfying predicate.
*/
updateAll: (
predicate: (item: T, index: number) => boolean,
newItem: T
) => void;
/**
* Removes an item at a particular index.
*/
removeAt: (index: number) => void;
/**
* Removes first item satisfying predicate.
*/
remove: (predicate: (item: T, index: number) => boolean) => void;
/**
* Removes all items satisfying predicate.
*/
removeAll: (predicate: (item: T, index: number) => boolean) => void;
/**
* Works like native `Array.filter`.
*/
filter: (
predicate: (value: T, index: number, array: T[]) => boolean,
thisArg?: any
) => void;
/**
* Works like native `Array.sort`.
*/
sort: (compareFn?: (a: T, b: T) => number) => void;
/**
* Works like native `Array.reverse`.
*/
reverse: () => void;
/**
* Resets list state to initial. Done through `useResetRecoilState`.
*/
reset: () => void;
}>;
Useful for managing state of global dialog windows like app theme, language, settings or confirmation dialog.
Created using dialogAtom
.
// atoms/dialogState.ts
import { dialogAtom } from 'recoil-tools';
export default dialogAtom<{ isDarkMode: boolean }>({
key: 'dialogState',
default: {
isOpen: false,
meta: { isDarkMode: false },
},
});
Access to the dialog state and setters is provided through useRecoilDialog
hook.
import { useRecoilDialog } from 'recoil-tools';
import dialogState from './atoms/dialogState';
function App() {
const [state, setters] = useRecoilDialog(dialogState);
}
You can also use only state's isOpen
property:
import { useRecoilDialogIsOpen } from 'recoil-tools';
import dialogState from './atoms/dialogState';
function App() {
const isOpen = useRecoilDialogIsOpen(dialogState);
}
Or only meta
property:
import { useRecoilDialogMeta } from 'recoil-tools';
import dialogState from './atoms/dialogState';
function App(): JSX.Element {
const { isDarkMode } = useRecoilDialogMeta(dialogState);
}
Or only state setters:
import { useRecoilDialogSetters } from 'recoil-tools';
import dialogState from './atoms/dialogState';
function App() {
const { open } = useRecoilDialogSetters(userListState);
}
type RecoilDialogState<T> = Readonly<{
/**
* Dialog open state.
*/
isOpen: boolean;
/**
* Any metadata related to the dialog.
*/
meta: T;
}>;
type RecoilDialogSetters<T> = Readonly<{
/**
* `isOpen` property setter.
*/
setOpen: SetterOrUpdater<boolean>;
/**
* Sets `isOpen` state to `true`. Also supports setting `meta` property.
*/
open: (meta?: T) => void;
/**
* Sets `isOpen` state to `false`.
*/
close: () => void;
/**
* `meta` property setter.
*/
setMeta: SetterOrUpdater<T>;
/**
* Resets dialog state to initial. Done through `useResetRecoilState`.
*/
reset: () => void;
}>;
Useful for storing and applying values used for filtering data.
Created using filtersAtom
.
// atoms/filtersState.ts
import { filtersAtom } from 'recoil-tools';
export default filtersAtom<{ isActive: boolean; categoryId: string }>({
key: 'filtersState',
default: {
isOpen: false,
isApplied: false,
values: { isActive: false, categoryId: '' },
},
});
Access to the filters state and setters is provided through useRecoilFilters
hook.
import { useRecoilFilters } from 'recoil-tools';
import filtersState from './atoms/filtersState';
function App() {
const [state, setters] = useRecoilFilters(filtersState);
}
You can also use only state's isOpen
property:
import { useRecoilFiltersIsOpen } from 'recoil-tools';
import filtersState from './atoms/filtersState';
function App() {
const isOpen = useRecoilFiltersIsOpen(filtersState);
}
Or only isApplied
property:
import { useRecoilFiltersIsApplied } from 'recoil-tools';
import filtersState from './atoms/filtersState';
function App() {
const isApplied = useRecoilFiltersIsApplied(filtersState);
}
Or only values
property:
import { useRecoilFiltersValues } from 'recoil-tools';
import filtersState from './atoms/filtersState';
function App() {
const values = useRecoilFiltersValues(filtersState);
}
Or only state setters:
import { useRecoilFiltersSetters } from 'recoil-tools';
import filtersState from './atoms/filtersState';
function App() {
const { apply } = useRecoilFiltersSetters(filtersState);
}
type RecoilFiltersState<T extends Record<string, any>> = Readonly<{
/**
* Filters open state.
*/
isOpen: boolean;
/**
* Whether filters have been applied.
*/
isApplied: boolean;
/**
* Filter values object.
*/
values: T;
}>;
type RecoilFiltersSetters<T extends Record<string, any>> = Readonly<{
/**
* `isOpen` property setter.
*/
setOpen: SetterOrUpdater<boolean>;
/**
* `isApplied` property setter.
*/
setApplied: SetterOrUpdater<boolean>;
/**
* Sets `isOpen` property to `true`.
*/
open: () => void;
/**
* Sets `isOpen` property to `false`.
*/
close: () => void;
/**
* Applies values by setting `values` property
* and `isApplied` property to `true`.
*/
apply: SetterOrUpdater<T>;
/**
* Resets filters state to initial. Done through `useResetRecoilState`.
*/
reset: () => void;
}>;
Static storage of pagination state.
Created using paginationAtom
.
// atoms/paginationState.ts
import { paginationAtom } from 'recoil-tools';
export default paginationAtom({
key: 'paginationState',
default: {
total: 0,
page: 1,
limit: 10,
offset: 0,
meta: undefined,
},
});
Access to the pagination state and setters is provided through useRecoilPagination
hook.
import { useRecoilPagination } from 'recoil-tools';
import paginationState from './atoms/paginationState';
function App() {
const [state, setters] = useRecoilPagination(paginationState);
}
You can also use only state setters:
import { useRecoilPaginationSetters } from 'recoil-tools';
import paginationState from './atoms/paginationState';
function App() {
const { setPage, setLimit } = useRecoilPaginationSetters(paginationState);
}
type RecoilPaginationState<T> = Readonly<{
/**
* Total number of records.
*/
total: number;
/**
* Current page number.
*/
page: number;
/**
* Number of records per page.
*/
limit: number;
/**
* Automatically calculated property based on `page` and `limit`
* that shows current offset in records.
*/
offset: number;
/**
* Any metadata related to the pagination.
*/
meta: T;
}>;
type RecoilPaginationSetters<T> = Readonly<{
/**
* `total` property setter.
*/
setTotal: SetterOrUpdater<number>;
/**
* `page` property setter.
*/
setPage: SetterOrUpdater<number>;
/**
* `limit` property setter.
*/
setLimit: SetterOrUpdater<number>;
/**
* `meta` property setter.
*/
setMeta: SetterOrUpdater<T>;
/**
* Resets pagination state to initial. Done through `useResetRecoilState`.
*/
reset: () => void;
}>;