Search code examples
javascriptreactjsreduxlodash

Redux, normalised entities and lodash merge


I'm using Redux, React and Lodash with a fairly standard normalized entities store.

When I merge in new entities in a redux reducer, the references to all my existing entities change (despite not being modified), causing any pure components to re-render.

Is there an alternative to lodash's merge that can merge whilst maintaining the existing references to values that are not in the object being merged in?

let entities = { 
  [1]: {a: true },
  [2]: {a: true, b: true },
}
let response = { 
  [2]: {a: false }
}
let newEntities = _.merge({}, entities, response)

console.log(entities[1] === newEntities[1]) // false

I can't use Object.assign/ES6 Spread here as then newEntities[2].b will be deleted.

I do realise there are alternative solutions such as custom sCU and reselect, however it would be much cleaner to take care of this at the reducer level rather than having to modify every single component that does an equality reference check on its props.


Solution

  • Use mergeWith with a customizer:

    let keepRef = (objValue, srcValue) => (
      objValue === undefined ? srcValue : _.mergeWith({}, objValue, srcValue, keepRef)
    )
    let newEntities = _.mergeWith({}, entities, response, keepRef)