A really small (~3kb/~1kb gziped) library to create an Entity Adapter¹² for Zustand.
It also allows you to create a convenient store that includes any additional structure and the actions and selectors to be used to manage the entities.
To install this library in your project, use npm :
npm install zustand-entity-adapter
or yarn:
yarn add zustand-entity-adapter
Here is a basic example of how to use the library.
Your adapter provides an API for manipulating and querying a normalized collection of state instances of the same type. It will allow you to create a normal Zustand store, and additionally to configure the actions and selectors for it.
import { create } from "zustand";
import { createEntityAdapter } from "zustand-entity-adapter";
// Define the entity
interface User {
id: number;
name: string;
}
// Create the entity adapter
const entityAdapter = createEntityAdapter<User, number>();
// Create the entity store
const useUserStore = create(entityAdapter.getState);
// Configure the entity actions
const userActions = entityAdapter.getActions(useUserStore.setState);
// Configure the entity selectors
const userSelectors = entityAdapter.getSelectors();You will be able to use the store as a regular store, and the selectors and actions without any additional binding.
const UserList: FC = () => {
const users = useUserStore(userSelectors.selectAll);
return (
<ul>
{users.map((user) => (
<li>{user.name}</li>
))}
</ul>
);
};
const AddUserButton: FC<{ user: User }> = ({ user }) => {
return <button onClick={() => userActions.addOne(user)}>Add user</button>;
};Alternatively, you can create an entity store and enjoy most of this configuration out the box.
// Create the entity store - One less type argument
const useUserStore = createEntityStore<User>();
// Configure the entity actions - No function calls, only properties
const userActions = useUserStore.actions;
// Configure the entity selectors
const userSelectors = useUserStore.selectors;The store and helpers can be used as described previously.
Creates an entity adapter for managing a normalized collection of entities of type Entity. This adapter provides methods for querying and updating the state, as well as actions for manipulating the entities.
-
Parameters:
options.idSelector(optional): A function that returns the entity ID.options.sort(optional): A function to sort the entities.
-
Methods:
getState(): Creates and returns the entity state.getActions(setState: SetState): Returns a set of actions to manipulate the entity state.getSelectors(): Provides selectors to query the state.
The selectors provided by getSelectors() are useful for querying the state.
selectIds(state: State): Returns an array of entity IDs.selectEntities(state: State): Returns a dictionary of entities by ID.selectAll(state: State): Returns an array of all entities.selectTotal(state: State): Returns the total count of entities.selectById(id: Id): Returns a specific entity by its ID.
The actions provided by getActions() allow manipulation of entities within the store.
addOne(entity: Entity): Adds a new entity to the collection.addMany(entities: Entity[]): Adds multiple entities to the collection.setOne(entity: Entity): Replaces an entity in the collection with the provided one.setMany(entities: Entity[]): Replaces multiple entities in the collection.setAll(entities: Entity[]): Replaces all entities with the provided set.updateOne(update: Update<Entity, Id>): Partially updates a single entity.updateMany(updates: Update<Entity, Id>[]): Partially updates multiple entities.upsertOne(entity: Entity): Inserts or updates a single entity.upsertMany(entities: Entity[]): Inserts or updates multiple entities.removeOne(id: Id): Removes an entity by its ID.removeMany(ids: Id[]): Removes multiple entities by their IDs.removeAll(): Removes allentities.
Creates an entity store using zustand, providing a full set of selectors and actions for managing entities.
-
Parameters:
options?: (optional) Configuration for sorting or ID selection. The same options thecreateEntityAdapterhas.stateCreator?: (optional) Function to create additional state in the store.actionsCreator?: (optional) Function to create custom actions.
-
Properties: The
createEntityStorereturns a regular Zustand store, with a state to manage the entities, and this properties:actions: The actions to manage the entities collection. The result of calling theEntityAdapter#getActionsmethod.selectors: The selector to query the entities collection. The result of calling theEntityAdapter#getSelectorsmethod.
-
Examples:
-
Basic store creation:
const useStore = createEntityStore<Entity>();
-
Store with additional state:
const useStore = createEntityStore( (): EntityState => ({ selectedUser: undefined }), );
-
Store with additional state and custom actions:
const useStore = createEntityStore( (): EntityState => ({ selectedUser: undefined, }), (set): EntityActions => ({ selectUser: (user) => set({ selectedUser: user }), }), );
-
Store with custom sorter:
const useStore = createEntityStore<Entity>({ sort: sorter });
-
Store with custom id selector (required if the model doesn't have an id property):
interface Product { sku: string; } const useStore = createEntityStore<Product, string>({ idSelector: (product) => product.sku, });
-
If you want to contribute to this project:
- Fork the repository.
- Create a new branch (
git checkout -b feature/new-feature). - Make the changes and commit them (
git commit -m 'Add new feature'). - Push the changes to the branch (
git push origin feature/new-feature). - Open a Pull Request.
This project is licensed under the MIT License. See the LICENSE file for more details.
This project could not exist without the amazing work from the @ngrx and the RTK teams.