rtfeldman / seamless-immutable

Immutable data structures for JavaScript which are backwards-compatible with normal JS Arrays and Objects.
BSD 3-Clause "New" or "Revised" License
5.37k stars 195 forks source link

Any chance mergeIn method will be implemented? #102

Closed smashercosmo closed 8 years ago

jschr commented 8 years ago

+1, would also love to have a complimentary withoutIn method as well to delete nested keys.

ie.

Immutable({ a: { b: 1, c: 2 } }).withoutIn(['a'], 'b')
// -> Immutable({ a: { c: 2 } })
rtfeldman commented 8 years ago

Not without a compelling motivating use case. :wink:

LinusU commented 8 years ago

@rtfeldman I just found out the hard way that there isn't a mergeIn method, I just assumed it was there :)

I think that there are some very compelling use cases. A common pattern in redux is to have a object with all entities, and then use different set that just contains the ids that corresponds to those objects. e.g. I have this object

{
  entities: {
    '1': { ... },
    '2': { ... },
    '3': { ... },
    ...
  },
  sets: {
    active: [1, 6, 9, 31, ...]
    needAction: [1, 3, 5, 6, ...]
  }
}

To then add more entities is a simple merge on the entities obejct. But it's important that it's not a deep merge so that removed properties will get properly removed when updating the entities. A mergeIn function would be perfect now

fetch('/animals?needAction=true')
  .then(res => res.json())
  .then(Immutable)
  .then(animals => {
    return state
      .setIn(['sets', 'needAction'], animals.map(animal => animal.id))
      .mergeIn(['entities'], animals.asObject(animal => [animal.id, animal]))
  }
}
smashercosmo commented 8 years ago

@LinusU That kind of data manipulation should occur only in reducers. I would keep sets and entities in different state slices and handle them with different reducers. And you won't need mergeIn for it.

LinusU commented 8 years ago

Yes it should be done in a reducer, I just wanted to show some code that made more sense for people not coming from redux...

I'm not use that I agree on having them in different reducers though, since the two properties are tightly coupled I don't see why they couldn't be manipulated by the same reducer?

braco commented 8 years ago

parent: { [parentId]: { children: { [id]: { ... } } } }

state.mergeIn(['parent', parentId, 'children', id], { merge me })

Is there anything that would be as clean as mergeIn above? It would be nice to have a completely flattened state, but this isn't always desirable.

withoutIn(), and some array methods would also be nice.

Dealing with deeply nested items is a pain, and there are already some patterns to build from starting with setIn(). Immutable.js has lots of methods like mergeDeep(), so there is precedence API wise. I'm finding the time originally saved by having normal objects with seamless is being eaten away by actually manipulating the data.

Maybe an alternative, more decorated version of seamless that adds convenience methods?

biirus commented 6 years ago

It seems to be trivial operation. For example, we have state shape:

const initialState = Immutable({
  someBusinessData: {},
  ui: {
    filters: {
      name: "",
      department: "",
    }
  }
})

And here is the reducer:

const reducer = (state = initialState, action) => {
    switch (action.type) {
      case "ui/change-filter": {
        return state.updateIn(["ui", "filter"], filter => filter.merge(action.payload));
      }
      default: 
        return state;
    }
}

mergeIn is just combination of updateIn and merge. So may be we should implement a shortcut method?

You can update a deeply nested parts of your state by mergeIn operation. It can apply patches to existing models (especially when you have normalised store and getting access by some ID prop), revert some optimistically updated values.

I think we should implement mergeIn method in seamless-immutable...