Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why immer.js doesn't allow setting dynamic properties on draft?

//I want my action to dispatch payload like
// {type:'update',payload:{'current.contact.mobile':'XXXXXXXXX'}}
//In reducer dynamically select the segment of state update needs to be applied to 
//Below code doesn't work as expected though, draft always remains at same level
draft = dA.key.split('.').reduce((draft, k) => {
  return draft[k]
}, draft);

//Or an ideal syntax may look like below line
draft['current.contact.mobile'] = dA.value;


//Code that works
draft['current']['contact']['mobile'] = dA.value;
I want my action to dispatch payload like {type:'update',payload:{'current.contact.mobile':'XXXXXXXXX'}} And in reducer dynamically select the segment of state that needs to be updated. Is there something fundamentally wrong in doing this, I believe this could make life easier. Is there something that can done to achieve this ?
like image 978
Viky293 Avatar asked Dec 27 '19 15:12

Viky293


1 Answers

In your case, this code returns a primitive value like a string or number which is immutable.

draft = dA.key.split('.').reduce((draft, k) => {
  return draft[k]
}, draft);

"Immer" is using Proxy to implement all this magic. The proxy could work only on objects for example Object, Array, Function etc.

so to fix your problem you can use code like this

import produce from "immer";

describe("Why immer.js doesn't allow setting dynamic properties on draft?", function() {
  it("should allow set dynamic properties", function() {
    const path = "foo.bar.zoo";
    const state = { foo: { bar: { zoo: 1 } } };
    const nextState = produce(state, draft => {
      const vector = path.split(".");
      const propName = vector.pop();

      if (propName) {
        draft = vector.reduce((it, prop) => it[prop], draft);
        draft[propName] += 1;
      }
    });

    expect(nextState.foo.bar.zoo).toEqual(state.foo.bar.zoo + 1);
  });
});

In the code above, we get destination object and update the property of this object.

Some note about string and number. Javascript has constructors for string and number which return objects not primitive values. But this is a very rare case when someone uses it explicitly. Usually, we deal with it implicitly when writing something like this dA.key.split('.'). In this case, the interpreter would create a string object and call method "split" on it. Usually, this behavior is referred to as "Boxing"

like image 98
maksimr Avatar answered Sep 20 '22 16:09

maksimr