Automated redux-state management for all your entities.
redux-entitize
helps you organize all your entities in unified and normalized state. It ships with:
- a reducer
- a set of action creators to populate your state with entity data
- a set of selectors to retrieve entities from the state
yarn add redux-entitize
# or
npm install --save redux-entitize
You need to tell redux-entitize about all your normalizr-schemas by defining a schemaMap
:
// schemaMap.js
import { normalize, schema } from 'normalizr';
const userSchema = new schema.Entity('users');
const commentSchema = new schema.Entity('comments', {
commenter: userSchema
});
export const schemaMap = {
users: userSchema,
comments: commentSchema,
};
// reducers.js
import { createEntitiesReducer } from 'redux-entitize';
import { combineReducers } from 'redux';
import { schemaMap } from './schemaMap';
const entitiesReducer = createEntitiesReducer(schemas);
export const reducers = combineReducers({
entities: entitiesReducer // must be called entities
// ... your other reducers
});
Note: In order for the selectors to Just Work™, the state slice must be called entities
.
To add new entities or update existing ones, use updateEntityAction
/ updateEntitiesAction
.
To remove an entity from your state, use deleteEntityAction
.
// main.js
import { createStore } from 'redux';
import {
updateEntityAction,
updateEntitiesAction,
deleteEntityAction,
} from 'redux-entitize';
import { reducers } from './reducers';
const store = createStore(reducers);
store.dispatch(
updateEntityAction('users', {
id: "1234",
email: "[email protected]",
age: 25,
})
);
store.dispatch(
updateEntitiesAction('comments', [{
id: "567",
message: "Hello world.",
commenter: "1234",
}, {
id: "890",
message: "Yet another comment. Even by the same commenter",
commenter: "1234",
}])
);
store.dispatch(
deleteEntityAction('comments', "567");
);
Note: Where these actions are actually dispatched is dependent on how your app is interacting with the API.
redux-entitize
provides a selectors factory to simplify selecting entities from the state. It's strongly recommended to use these, because
- selected entities will be automatically de-normalized
- selectors are based on reselect, so they are memoized (otherwise you application will most likely be slow)
- selectors are meant to remain stable throughout changes of the internal
entities
-state
// selectors.js
import { createSelectors } from 'redux-entitize';
// Assuming we have that `schemaMap` variable from above when you created your schemas
import { schemaMap } from './schemaMap'
export const selectors = createSelectors(schemaMap)
Import the selectors in your components and render data as you like.
// UserList.js
import React from 'react';
import { connect } from 'react-redux';
import UserList './UserList';
import {
selectEntity,
selectEntities
} from './selectors';
function mapStateToProps(state) {
return {
// Get all entities of a type
allUsers: selectEntities(state, 'users'),
// Get all entities of a type with certain IDs
// (state.userList.filteredIds === ['id1', 'id2', 'id3'])
filteredUsers: selectEntities(state, 'users', state.userList.filteredIds),
// Get a single entity of a type with a certain ID
// (state.login.userId === 'id123')
loggedInUser: selectEntity(state, 'users', state.login.userId)
};
}
export default connect(mapStateToProps)(UserList);