immutable-gene

1.0.2 • Public • Published

immutable-gene

clean your boilerplate code inside reducers

Utility library that will help you clean mess in your flux/redux reducers. It updates state and returns brand new object with configured modifications.

    npm install --save immutable-gene

Quick start

    import {Gene} from 'immutable-gene';
 
    let state:any = { a: { b: {c: [{id:1, name:'jon'}, {id:2, name:'bob'}]}}};
    let result = Gene.mutate(state)
        .update('a.b.c[id=1]', {name: 'josh'})
        .push('a.b.c', {id: 3, name: 'zofia'})
        .value();
 
    //result:
    //state = { a: { b: {c: [{id=1, name='josh'}, {id=2, name='bob'}, {id=3, name='zofia'}]}}};
    import {Gene} from 'immutable-gene';
 
    let state:any ={groups: [
                        {
                          "name": "sit",
                          "users": [
                            {"id": 0, "name": "Lara Lowery"},
                            {"id": 1, "name": "Gayle Whitfield"},
                            {"id": 2, "name": "Shaw Schmidt"}]
                        },
                        {
                          "name": "ad",
                          "users": [
                            {"id": 3, "name": "Ruby Pickett"},
                            {"id": 4, "name": "Campos Flowers"},
                            {"id": 5,  "name": "Kirkland Faulkner"}
                          ]
                        }]};
    let userId = 4;
    let result = Gene.update(state, ['groups[*].users[id=?]', userId], {name: 'XYZ'})
    //it is flattening group collection and looks on each of them for user with id = 4 and updates its name to XYX
    //result:
    //              {groups: [
    //                     {
    //                       "name": "sit",
    //                       "users": [
    //                         {"id": 0, "name": "Lara Lowery"},
    //                         {"id": 1, "name": "Gayle Whitfield"},
    //                         {"id": 2, "name": "Shaw Schmidt"}]
    //                     },
    //                     {
    //                       "name": "ad",
    //                       "users": [
    //                         {"id": 3, "name": "Ruby Pickett"},
    //                         {"id": 4, "name": "XYZ"},
    //                         {"id": 5,  "name": "Kirkland Faulkner"}
    //                       ]
    //                     }]};

supported methods :

  • Gene.update(state, selector, object) - updates nested object found by selector like assign(i, x) from lodash
  • Gene.push(state, selector, object) - adds object to nested array
  • Gene.remove(state, selector) - removes object from array or from parent object
  • Gene.mutate(state) - allows fluid interfacet for chainig update operations.. to get final result invoke .value() method

slecotrs

it uses json-query npm package under the hood so it suports all selectors from this awesome packange: https://www.npmjs.com/package/json-query

for example:

Array filter

By default only the first matching item will be returned:

people[name=Matt]

But if you add an asterisk (*), all matching items will be returned:

people[*country=NZ]

You can use comparative operators:

people[*rating>=3]

Motivation

Most of reducer code in any flux implementation looks like below:

 
export default function todos(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        {
          id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1,
          completed: false,
          text: action.text
        },
        ...state
      ]
 
    case DELETE_TODO:
      return state.filter(todo =>
        todo.id !== action.id
      )
 
    case EDIT_TODO:
      return state.map(todo =>
        todo.id === action.id ?
          { ...todo, text: action.text } :
          todo
      )
 
    case COMPLETE_TODO:
      return state.map(todo =>
        todo.id === action.id ?
          { ...todo, completed: !todo.completed } :
          todo
      )
 
    case COMPLETE_ALL:
      const areAllMarked = state.every(todo => todo.completed)
      return state.map(todo => ({
        ...todo,
        completed: !areAllMarked
      }))
 
    case CLEAR_COMPLETED:
      return state.filter(todo => todo.completed === false)
 
    default:
      return state
  }
}
 

It's pretty messy, hard to read and hard to write. And above exaple is just a simple case scenario. situation is getting more comlicated when you try to update some nested property in your state.

With usage of immutable-bene above code would look like below:

 
export default function todos(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      return Gene.push(sate, '', {
                                   id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1,
                                   completed: false,
                                   text: action.text
                                 });
    case DELETE_TODO:
      return Gene.remove(state, ['[id=?]', action.id]);
 
    case EDIT_TODO:
      return Gene.update(state, ['[id=?]', action.id], {text: action.text });
 
    case COMPLETE_TODO:
      return Gene.update(state, ['[id=?]', action.id], {completed: true });
 
    case COMPLETE_ALL:
      const areAllMarked = state.every(todo => todo.completed)
      return Gene.update(state, '', {completed: areAllMarked });
 
    case CLEAR_COMPLETED:
      return state.filter(todo => todo.completed === false)
 
    default:
      return state
  }
}
 

Dependents (0)

Package Sidebar

Install

npm i immutable-gene

Weekly Downloads

0

Version

1.0.2

License

MIT

Last publish

Collaborators

  • mmajewski