Recoil is an experimental state management framework for React applications that provides atoms and selectors for fine-grained reactivity.
npx @tessl/cli install tessl/npm-recoil@0.7.0Recoil is an experimental React state management framework that provides fine-grained reactivity through atoms (units of state) and selectors (derived state). It offers minimal boilerplate with automatic optimization, where components only re-render when specific state they depend on changes, and includes built-in support for asynchronous operations and concurrent React features.
npm install recoilimport {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
useSetRecoilState
} from "recoil";CommonJS:
const {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
useSetRecoilState
} = require("recoil");import React from 'react';
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
} from 'recoil';
// Define atoms (state)
const textState = atom({
key: 'textState',
default: '',
});
// Define selectors (derived state)
const charCountState = selector({
key: 'charCountState',
get: ({get}) => {
const text = get(textState);
return text.length;
},
});
// Component using Recoil state
function TextInput() {
const [text, setText] = useRecoilState(textState);
return (
<input
value={text}
onChange={(e) => setText(e.target.value)}
/>
);
}
function CharacterCount() {
const count = useRecoilValue(charCountState);
return <div>Character Count: {count}</div>;
}
// App with RecoilRoot
function App() {
return (
<RecoilRoot>
<TextInput />
<CharacterCount />
</RecoilRoot>
);
}Recoil is built around several key concepts:
Core component for managing Recoil state throughout your React application.
interface RecoilRootProps {
initializeState?: (mutableSnapshot: MutableSnapshot) => void;
override?: boolean;
children: React.ReactNode;
}
const RecoilRoot: React.FC<RecoilRootProps>;Core functions for defining atoms and selectors that form the state graph.
interface AtomOptions<T> {
key: string;
default?: T | RecoilValue<T> | Promise<T> | Loadable<T> | WrappedValue<T>;
effects?: ReadonlyArray<AtomEffect<T>>;
dangerouslyAllowMutability?: boolean;
}
function atom<T>(options: AtomOptions<T>): RecoilState<T>;
interface ReadOnlySelectorOptions<T> {
key: string;
get: (opts: { get: GetRecoilValue; getCallback: GetCallback }) =>
T | RecoilValue<T> | Promise<T> | Loadable<T> | WrappedValue<T>;
cachePolicy_UNSTABLE?: CachePolicyWithoutEquality;
dangerouslyAllowMutability?: boolean;
}
interface ReadWriteSelectorOptions<T> extends ReadOnlySelectorOptions<T> {
set: (opts: {
set: SetRecoilState;
get: GetRecoilValue;
reset: ResetRecoilState;
}, newValue: T | DefaultValue) => void;
}
function selector<T>(options: ReadWriteSelectorOptions<T>): RecoilState<T>;
function selector<T>(options: ReadOnlySelectorOptions<T>): RecoilValueReadOnly<T>;Essential React hooks for reading and writing Recoil state with automatic subscriptions.
function useRecoilValue<T>(recoilValue: RecoilValue<T>): T;
function useRecoilState<T>(recoilState: RecoilState<T>): [T, SetterOrUpdater<T>];
function useSetRecoilState<T>(recoilState: RecoilState<T>): SetterOrUpdater<T>;
function useResetRecoilState(recoilState: RecoilState<any>): () => void;
function useRecoilValueLoadable<T>(recoilValue: RecoilValue<T>): Loadable<T>;
function useRecoilStateLoadable<T>(recoilState: RecoilState<T>): [Loadable<T>, SetterOrUpdater<T>];Functions for creating parameterized atoms and selectors that are memoized by parameter.
function atomFamily<T, P extends SerializableParam>(
options: AtomFamilyOptions<T, P>
): (param: P) => RecoilState<T>;
function selectorFamily<T, P extends SerializableParam>(
options: ReadWriteSelectorFamilyOptions<T, P>
): (param: P) => RecoilState<T>;
function selectorFamily<T, P extends SerializableParam>(
options: ReadOnlySelectorFamilyOptions<T, P>
): (param: P) => RecoilValueReadOnly<T>;Utilities for coordinating multiple async operations and handling loading states.
function noWait<T>(state: RecoilValue<T>): RecoilValueReadOnly<Loadable<T>>;
function waitForAll<T extends Array<RecoilValue<any>>>(
param: T
): RecoilValueReadOnly<UnwrapRecoilValues<T>>;
function waitForNone<T extends Array<RecoilValue<any>>>(
param: T
): RecoilValueReadOnly<UnwrapRecoilValueLoadables<T>>;Powerful hooks for complex operations including callbacks, transactions, and state introspection.
function useRecoilCallback<Args extends ReadonlyArray<unknown>, Return>(
fn: (interface: CallbackInterface) => (...args: Args) => Return,
deps?: ReadonlyArray<unknown>
): (...args: Args) => Return;
function useRecoilSnapshot(): Snapshot;
function useGotoRecoilSnapshot(): (snapshot: Snapshot) => void;System for handling async state with loading, error, and success states.
type Loadable<T> = ValueLoadable<T> | LoadingLoadable<T> | ErrorLoadable<T>;
interface ValueLoadable<T> {
state: 'hasValue';
contents: T;
getValue(): T;
valueOrThrow(): T;
}
namespace RecoilLoadable {
function of<T>(x: T | Promise<T> | Loadable<T>): Loadable<T>;
function error(x: any): ErrorLoadable<any>;
function loading(): LoadingLoadable<any>;
}Tools for managing memory usage and preventing unwanted garbage collection of state.
function useRetain(
toRetain: RecoilValue<any> | RetentionZone | Array<RecoilValue<any> | RetentionZone>
): void;
function retentionZone(): RetentionZone;// Base types
type NodeKey = string;
type SerializableParam =
| undefined | null | boolean | number | symbol | string
| ReadonlyArray<SerializableParam>
| ReadonlySet<SerializableParam>
| Readonly<{[key: string]: SerializableParam}>;
// ID types
interface StoreID {
readonly [StoreID_OPAQUE]: true;
}
interface SnapshotID {
readonly [SnapshotID_OPAQUE]: true;
}
// Snapshot types
class Snapshot {
getID(): SnapshotID;
getLoadable<T>(recoilValue: RecoilValue<T>): Loadable<T>;
getPromise<T>(recoilValue: RecoilValue<T>): Promise<T>;
getNodes_UNSTABLE(opts?: { isModified?: boolean; isInitialized?: boolean }): Iterable<RecoilValue<unknown>>;
getInfo_UNSTABLE<T>(recoilValue: RecoilValue<T>): RecoilStateInfo<T>;
map(cb: (mutableSnapshot: MutableSnapshot) => void): Snapshot;
asyncMap(cb: (mutableSnapshot: MutableSnapshot) => Promise<void>): Promise<Snapshot>;
retain(): () => void;
isRetained(): boolean;
}
class MutableSnapshot extends Snapshot {
set: SetRecoilState;
reset: ResetRecoilState;
}
// State info for debugging
interface RecoilStateInfo<T> {
loadable?: Loadable<T>;
isActive: boolean;
isSet: boolean;
isModified: boolean;
type: 'atom' | 'selector';
deps: Iterable<RecoilValue<T>>;
subscribers: {
nodes: Iterable<RecoilValue<T>>;
components: Iterable<ComponentInfo>;
};
}
interface ComponentInfo {
name: string;
}
// State types
class RecoilState<T> {
key: NodeKey;
toJSON(): {key: string};
}
class RecoilValueReadOnly<T> {
key: NodeKey;
toJSON(): {key: string};
}
type RecoilValue<T> = RecoilValueReadOnly<T> | RecoilState<T>;
// Special values
class DefaultValue {
private __tag: 'DefaultValue';
}
interface WrappedValue<T> {
readonly [WrappedValue_OPAQUE]: true;
}
// Function types
type SetterOrUpdater<T> = (valOrUpdater: ((currVal: T) => T) | T) => void;
type GetRecoilValue = <T>(recoilVal: RecoilValue<T>) => T;
type SetRecoilState = <T>(
recoilVal: RecoilState<T>,
newVal: T | DefaultValue | ((prevValue: T) => T | DefaultValue)
) => void;
type ResetRecoilState = (recoilVal: RecoilState<any>) => void;
type GetCallback = <Args extends ReadonlyArray<unknown>, Return>(
fn: (interface: SelectorCallbackInterface) => (...args: Args) => Return
) => (...args: Args) => Return;
// Selector callback interface
interface SelectorCallbackInterface extends CallbackInterface {
node: RecoilState<unknown>;
}
// Utility function
function isRecoilValue(val: unknown): val is RecoilValue<any>;