selector
Among other things, selectors enable:
- Computing derived state:
- synchronously or asynchronously
- with updates triggered by changes in dependencies
- as either a consumer or a dependency of other derived state
- Performing side effects, such as data fetching
const selector: <T>(
selectorFn: SelectorFn<T>,
options?: SelectorOptions,
) => Scoped<ReadonlyState<T>>;
-
selectorFn
- The function that produces the derived value (invoked every time the selector needs to re-evaluate). It has the following signature:<T>(arg: { get: GetFn; signal: AbortSignal }) => T
, where:-
get
- A getter function used to consume the selector's dependencies (atoms or other selectors) or other selectors). Callingget
with aState
instance adds that state to the selector's dependency set, meaning the selector will re-evaluate whenever that state changes.infoThe dependency graph in Stan is dynamic, meaning
get
can also be called conditionally. The order of calls doesn't matter either. Stan will update the dependency graph and unsubscribe from dependencies that are no longer needed. -
signal
- AnAbortSignal
instance associated with the currentselectorFn
call. The next timeselectorFn
is called, thesignal
from the previous call will be aborted (using an instance ofAborted
, a Stan-specific subclass ofError
). This is useful for canceling ongoing work, such as HTTP requests.
-
-
options?
- Selector configuration:-
tag?
- A string that gets appended to thekey
(seeState<T>
). Useful for debugging. -
areValuesEqual?
- A function used to determine whether two consecutive selector values are equal. It has the following signature:<T>(a: T, b: T) => boolean
, and defaults to a simplea === b
check. If this function returnstrue
(or any other truthy value) upon computing the selector's value, the value is considered unchanged, and no subscribers will be notified.infoareValuesEqual
is expected to be synchronous.This means, in particular, that a
Promise
returned from an asynchronous selector will (by default) always be considered a different value unless:- it is the exact same
Promise
(reference equality), or - it can be determined synchronously (e.g.,
(a, b) => a.prop === b.prop
) that the values are effectively the same.
In general,
areValuesEqual
should be considered a cheap, simple optimization - nothing more. - it is the exact same
-
Example
Add two numbers:
const sum = selector(() => 40 + 2);
Add two dynamic numbers:
const num1 = atom(40);
const num2 = atom(2);
const sum = selector(({ get }) => get(num1) + get(num2));
Add two dynamic async numbers:
const num1 = selector(() => getNum1());
const num2 = selector(() => getNum2());
const sum = selector(async ({ get }) => {
const [n1, n2] = await Promise.all([get(num1), get(num2)]);
return n1 + n2;
});
Render with React:
const MyComponent: FC = () => {
const result = useStanValueAsync(sum);
switch (result.type) {
case 'loading':
return <p>Loading…</p>;
case 'error':
return <p>Nope</p>;
case 'ready':
return <p>{result.value}</p>;
}
};
See also
selectorFamily
- Using Stan with React
- Aborting work (example)
- Asynchronous state (example)
- Dynamic dependencies (example)