# Normalising Data with createEntityAdapter — Redux Toolkit / Zustand

Source: https://www.skillbyai.com/en/redux-zustand/p-entities

> ids plus a lookup table.

## Store each item once

Nested or duplicated data is hard to update consistently. **Normalised** state keeps each collection as `{ ids: [], entities: {} }`: an ordered array of IDs and an object mapping ID to item, with relations stored as IDs. `createEntityAdapter` produces this shape with `getInitialState()`, provides CRUD reducer helpers (`addOne`, `addMany`, `setAll`, `upsertMany`, `updateOne`, `removeOne` and more) usable directly as case reducers or inside them, and generates selectors (`selectAll`, `selectById`, `selectIds`, `selectEntities`, `selectTotal`). An optional `sortComparer` keeps `ids` sorted.

## Shape state for fast lookups

Normalised data, memoised selectors and visible middleware keep big stores manageable.

![Three ideas: createEntityAdapter, createSelector, middleware and DevTools.](assets/figures/redux-zustand/section-5-map.svg) — Figure 5.1 — Normalised entities feeding memoised selectors.

## A todos adapter

Adapter, slice and selectors.

```typescript
import { createEntityAdapter, createSlice, type PayloadAction } from '@reduxjs/toolkit';

type Todo = { id: string; text: string; done: boolean };

const todosAdapter = createEntityAdapter<Todo>({
  sortComparer: (a, b) => a.text.localeCompare(b.text),
});

const todosSlice = createSlice({
  name: 'todos',
  initialState: todosAdapter.getInitialState({ filter: 'all' as 'all' | 'open' }),
  reducers: {
    todoAdded: todosAdapter.addOne,
    todosLoaded: todosAdapter.setAll,
    todoToggled(state, action: PayloadAction<string>) {
      const todo = state.entities[action.payload];
      if (todo) todo.done = !todo.done;
    },
  },
});

export const { selectAll: selectAllTodos, selectById: selectTodoById } =
  todosAdapter.getSelectors((state: RootState) => state.todos);
```

## A library catalogue

Books sit once on numbered shelves (entities); reading lists only hold catalogue numbers (ids). Fix a typo in a title and every list that refers to it is correct.

**Quiz:** What shape does createEntityAdapter give a collection?

- [ ] A nested tree of objects
- [x] An ids array plus an entities lookup object
- [ ] A Map stored in state
- [ ] A plain array only

*Answer:* An ids array plus an entities lookup object. Normalised state makes lookups and updates O(1) by ID.
