为什么 immer.js 不允许在草稿上设置动态属性?

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;
我希望我的动作像 {类型:'update',有效载荷:{'current.contact.mobile':'XXXXXXXXX'}} 并且在 reducer 中动态 select 需要更新的状态段。 这样做有什么根本性的错误吗,我相信这可以让生活更轻松。有什么办法可以实现这一目标吗?

在您的情况下,此代码 returns a primitive value 类似于不可变的字符串或数字。

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

"Immer" 正在使用 Proxy 来实现所有这些魔法。代理只能在对象上工作,例如对象、数组、函数等。

所以要解决您的问题,您可以使用这样的代码

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);
  });
});

在上面的代码中,我们获取目标对象更新此对象的属性

关于字符串和数字的一些注意事项。 Javascript 有 constructors 用于字符串和数字,其中 return 对象 不是原始值。但当有人明确使用它时,这种情况非常罕见。 通常,我们在写这样的东西时会隐式地处理它dA.key.split('.')。在这种情况下,解释器将创建一个字符串对象并在其上调用方法 "split"。通常,这种行为被称为“拳击