Security News
Highlights from the 2024 Rails Community Survey
A record 2,709 developers participated in the 2024 Ruby on Rails Community Survey, revealing key tools, practices, and trends shaping the Rails ecosystem.
A simple ORM to manage and query your state trees, so you can write your reducers like this:
import {EntityManager, Schema} from 'redux-orm';
const PeopleManager = EntityManager.extend({schema: new Schema('people')});
function peopleReducer(state, action) => {
const peopleManager = new PeopleManager(state);
switch (action.type) {
case CREATE_PERSON:
peopleManager.create(action.payload);
break;
case SET_AGE:
peopleManager.get({id: action.payload.id}).set('age', action.payload.age);
break;
case DELETE_PERSON:
peopleManager.get({id: action.payload.id}).delete();
break;
case DELETE_YOUNGEST_AND_OLDEST_PERSON:
const orderedByAge = peopleManager.orderBy('age');
orderedByAge.first().delete();
orderedByAge.last().delete();
break;
case ODD_CHANGE:
peopleManager.filter(person => person.age > 29).exclude({name: 'Mary'}).update({age: 100});
break;
default:
return state;
}
// Return a copy of the state tree with mutations applied.
return peopleManager.reduce();
}
The API is heavily inspired by the Django ORM.
npm install --save redux-orm
Import module.
import {Schema, EntityManager} from 'redux-orm';
Declare your managers.
const peopleSchema = new Schema('people', {idAttribute: 'id'});
const PeopleManager = EntityManager.extend({schema: peopleSchema});
Then you can instantiate PeopleManager
with a state tree when you need.
const tree = {
people: [0],
peopleById: {
0: {
name: 'Tommi',
age: 25
},
},
};
const people = new PeopleManager(tree);
Use the manager in your reducers.
function peopleReducer(state, action) {
const people = new PeopleManager(state);
switch (action.type) {
// Handle actions
case CRAZY_ACTION:
// Record mutations with `people`
people.create({name: 'John', age: 50});
people.get({name: 'Tommi'}).delete();
break;
default:
return state;
}
// Return a copy of the original tree with
// mutations applied.
return people.reduce();
}
function rootReducer(state, action) {
return {
people: peopleReducer(state, action),
};
}
You can use it in your React components too.
import {EntityManager, Schema} from 'redux-orm';
const RD = React.DOM;
const PeopleManager = EntityManager.extend({schema: new Schema('people', {idAttribute: 'id'})});
const PeopleViewer = React.createClass({
propTypes: {
people: React.PropTypes.arrayOf(React.PropTypes.number).isRequired,
peopleById: React.PropTypes.object.isRequired,
},
getDefaultProps() {
return {
people: [],
peopleById: {},
};
}
renderList(querySet) {
const chilren = querySet.getPlainEntities().map(person => {
return RD.li({key: person.id}, `${person.name}, ${person.age}`);
});
return RD.ul(null, children);
}
render() {
const people = new PeopleManager(this.props);
const youngPeople = people.filter(person => person.age < 40);
const coolAndYoungPeople = youngPeople.exclude({square: true});
const youngList = this.renderList(youngPeople);
const coolAndYoungList = this.renderList(coolAndYoungPeople);
return RD.div(null, youngList, coolAndYoungList);
}
});
If you're storing items in your redux
state tree this way:
const tree = {
people: [0, 1, 2],
peopleById: {
0: {
name: 'Tommi',
age: 25
},
1: {
name: 'John',
age: 35
},
2: {
name: 'Mary',
age: 30
}
}
};
You'll end up writing quite a bit of boilerplate to handle create, update and delete operations, especially if you're doing it in pure JS. Libraries like Immutable can help considerably.
function peopleReducer(state, action) {
switch (action.type) {
case CREATE_PERSON:
return [...state, action.payload.id];
case DELETE_PERSON:
const personIdx = state.indexOf(action.payload);
return [...state.slice(0, personIdx), ...state.slice(personIdx + 1)];
default:
return state;
}
}
function peopleByIdReducer(state, action) {
switch (action.type) {
case CREATE_PERSON:
const personWithoutId = Object.keys(action.payload).filter(key => key !== 'id')
return {
...state,
[action.payload.id]: omit(action.payload, 'id'),
};
case DELETE_PERSON:
return omit(state, action.payload);
case UPDATE_PERSON:
const prevPerson = state[action.payload.id];
return {
...state,
[action.payload.id]: Object.assign({}, prevPerson, omit(action.payload, 'id')),
};
default:
return state;
}
}
If you have different entity types, you'll be writing a lot of boilerplate. The bugs are bound to creep in at some point. redux-orm
abstracts this particular way of working with entities.
See the full documentation for EntityManager here.
Methods:
get
to get an entity based on properties,create
to create a new instance. The new id
will be Math.max(...allOtherIds) + 1
unless you set it explicitly.reduce
makes a copy of the state tree with the recorded mutations appliedMethods shared with QuerySet:
getPlainEntities
: returns the entities as an array of objects with the id
attribute included.count
: returns the number of entities.exists
: return true
if number of entities is more than 0, else false
.filter
: returns a new QuerySet
with the entities that pass the filter.exclude
returns a new QuerySet
with the entities that do not pass the filter.all
return a new QuerySet
with the same entities.at
returns an Entity
instance at the supplied index.first
returns an Entity
instance at the 0
index.last
returns an Entity
instance at the EntityManager.count() - 1
index.delete
marks all the entities for deletion on reduce
.update
marks all the entities for an update based on the supplied argument.See the full documentation for Schema here.
Schema
holds information about the schema. If you pass a single string arguments, the generated tree will look like this:
const schema = new Schema('items');
// Resulting empty tree: {items: [], itemsById: {}}
You can pass an optional options object. The defaults are:
{
idAttribute: 'id',
arrName: 'items', // if not specified, this is the same as the frst argument.
mapName: 'itemsById', // if not specified, this is the first argument + `'ById'`.
}
See the full documentation for QuerySet
here.
Methods:
getPlainEntities
: returns the QuerySet
entities as an array of objects with the id
attribute included.count
: returns the number of entities in the QuerySet
.exists
: return true
if number of entities is more than 0, else false
.filter
: returns a new QuerySet
with the entities that pass the filter.exclude
returns a new QuerySet
with the entities that do not pass the filter.all
return a new QuerySet
with the same entities.at
returns an Entity
instance at the supplied index in the QuerySet
.first
returns an Entity
instance at the 0
index.last
returns an Entity
instance at the EntityManager.count() - 1
index.delete
marks all the QuerySet
entities for deletion on reduce
.update
marks all the QuerySet
entities for an update based on the supplied argument.See the full documentation for Entity
here.
Methods:
set
: marks a supplied propertyName
to be updated to value
at reduce
.update
: marks a supplied object of property names and values to be merged with the entity at reduce
.delete
: marks the entity to be deleted at reduce
.MIT. See LICENSE
FAQs
Simple ORM to manage and query your state trees
The npm package redux-orm receives a total of 2,984 weekly downloads. As such, redux-orm popularity was classified as popular.
We found that redux-orm demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A record 2,709 developers participated in the 2024 Ruby on Rails Community Survey, revealing key tools, practices, and trends shaping the Rails ecosystem.
Security News
In 2023, data breaches surged 78% from zero-day and supply chain attacks, but developers are still buried under alerts that are unable to prevent these threats.
Security News
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.