Search code examples
javascriptecmascript-6reduxsyntactic-sugarecmascript-2016

Drill down into multi-nested arrays syntactic sugar


I often find myself following this pattern when I need to drill down into a data-structure, especially in my Redux reducers:

state.items = state.items.map((item) => {
  item.subItems = item.subItems.map((subItem) => {
    subItem.bottomItems = subItem.bottomItems.map((bottomItem) => {
      // do something with bottomItem...
      bottomItem.foo = 'bar';
      return bottomItem;
    });
    return subItem;
  });
  return item;
});

This seems like a lot of boilerplate to get down to the bottomItems level.

Does ES6 or ES7 provide some syntactic sugar to ease this pattern?


Solution

  • First thing I should mention is that the code you have there modifies the original state. To maintain the state immutability principle of redux, you want to only return new objects and not modify existing ones along the way.

    As far as a simpler syntax, if you use arrow functions and object spread, this pattern isn't that bad:

    return {
      items: state.items.map(item => ({
        ...item,
        subItems: item.subItems.map(subItem => ({
          ...subItem,
          bottomItems: subItem.bottomItems.map(bottomItem => ({
            ...bottomItem,
            foo: 'bar' // update foo to 'bar' for every bottomItem in every subItem in every item
          })
        })
      })
    }
    

    Note that object spread is not part of the language yet, it is currently a stage 3 proposal and will likely be part of one of the next ECMAScript releases. Therefore, you must transpile it with something like Babel to work in today's browsers.

    If you do not wish to do this and want features natively available today, you can use Object.assign instead:

    return {
      items: state.items.map(item => Object.assign({}, item, {
        subItems: item.subItems.map(subItem => Object.assign({}, subItem, {
          bottomItems: subItem.bottomItems.map(bottomItem => Object.assign({}, bottomItem, {
            foo: 'bar' // update foo to 'bar' for every bottomItem in every subItem in every item
          })
        })
      })
    }
    

    Since it seems that you want a cleaner, more readable syntax, I suggest option 1 :)