Skip to main content

Selector

Selectors derive state from boxes or other selectors.

import { selector } from 'amos';

const selectCountLabel = selector((select) => {
return `Count: ${select(countBox)}`;
});

Call a selector factory to create a selector, then pass it to select or useSelector.

const label = store.select(selectCountLabel());

Selector Arguments​

Selectors can accept arguments.

const selectTodoTitle = selector((select, id: number) => {
return select(todoMapBox.getIn(id, 'title'));
});

select(selectTodoTitle(1));

The arguments are stored on the selector object. Devtools and cache keys can use them.

Composing Selectors​

Selectors receive the same select function as the store.

const selectCurrentUser = selector((select) => {
return select(userMapBox.getItem(select(currentUserIdBox)));
});

This makes selectors easy to compose without a global root-state type.

Equality​

Selectors can define equality for React updates.

const selectUserSummary = selector(
(select, id: number) => {
const user = select(userMapBox.getItem(id));
return { id: user.id, name: user.name };
},
{ equal: shallowEqual },
);

Uncached selectors use their equal function when useSelector decides whether to re-render.

Cache​

Set cache: true for expensive selectors or selectors that return reusable objects.

const selectVisibleTodos = selector(
(select) => {
const status = select(todoStatusFilterBox);
const ids = select(selectUserTodoList());

return ids.filter((id) => {
const todo = select(todoMapBox.getItem(id));
return status === 'All' || todo.completed === (status === 'Completed');
});
},
{ cache: true },
);

Cached selectors track which boxes and selectors they selected. Amos reuses the cached result while those dependencies are equal.

Row Loading​

Box selectors can declare which persisted row they read.

select(todoMapBox.getItem(id));

For MapBox, getItem(id) declares that it loads row id. The persistence enhancer can hydrate that row lazily.

You usually only need to think about loadRow when creating custom boxes.