Entity adapter
Keep collections normalized as ordered IDs and an entity record, with helpers that work inside your slice handlers.
Define IDs and ordering
createEntityAdapter<T> requires both selectId(entity): string and sortComparer(a, b): number. getInitialState() creates { ids: [], entities: {} }; an optional object adds extra fields. Get fresh adapter state for every store. IDs must be unique strings, including input passed to setAll.
import { configureStore, createEntityAdapter, createEvent, createSlice } from "@carere/solux";
type Task = { id: string; title: string };
const tasks = createEntityAdapter<Task>({
selectId: (task) => task.id,
sortComparer: (a, b) => a.title.localeCompare(b.title),
});
const taskAdded = createEvent<Task>("tasks/added");
const slice = createSlice({
initialState: tasks.getInitialState({ loading: false }),
handlers: (builder) => builder.addHandler(taskAdded, (state, { payload }) => {
tasks.addOne(state, payload);
}),
});
const store = configureStore({ rootSlice: slice });
store.dispatch(taskAdded({ id: "docs", title: "Read Solux docs" }));
const selectors = tasks.getSelectors();
console.log(selectors.selectAll(store.state));Choose the right operation
Add and set helpers recompute the ID ordering with sortComparer. There are no updateOne or upsertOne methods; use setOne with a complete entity to replace one. These helpers mutate the state they receive, so use them in handlers or on state you own.
| Operation | Behavior |
|---|---|
addOne / addMany | Insert new IDs. Existing entities are retained, not merged or replaced. |
setOne / setMany | Insert or replace whole entities by ID. Other entities remain. |
setAll | Replace the entire collection. Pass unique IDs; the input array is sorted in place. |
removeOne / removeMany | Remove the supplied string ID or IDs from both collections. |
removeAll | Clear IDs and entities; preserve extra state fields. |
Select inside a reactive scope
getSelectors() supplies selectIds, selectEntities, selectAll, selectTotal, and selectById. selectById returns undefined for a missing ID. Pass a selectState function to getSelectors to target a collection nested in a root state. Selectors are ordinary functions, not memoized computations: call them inside JSX or wrap the result in createMemo when useful.
import { combineSlices } from "@carere/solux";
import { createMemo } from "solid-js";
const nestedStore = configureStore({
rootSlice: combineSlices({
tasks: createSlice({
initialState: tasks.getInitialState(),
handlers: (builder) => builder.addHandler(taskAdded, (state, { payload }) => {
tasks.addOne(state, payload);
}),
}),
}),
});
type RootState = typeof nestedStore.state;
const rootSelectors = tasks.getSelectors<RootState, RootState["tasks"]>(
(state) => state.tasks,
);
const all = createMemo(() => rootSelectors.selectAll(nestedStore.state));