代码之家  ›  专栏  ›  技术社区  ›  Brian Ogden

在react.js状态下正确更新对象而不使用spread运算符

  •  0
  • Brian Ogden  · 技术社区  · 6 年前

    扩散算子 ... 是Visual Studio或Resharper Intellisense的实验级功能,我正在使用Ecmascript 2015: enter image description here

    我正在使用babel,我看到了transpiled source中的spread操作符: enter image description here

    因此,我尝试用object.assign替换spread运算符功能,以便在处于反应状态的对象上进行更新。

    使用Spread运算符,我可以使用以下命令更新对象的状态:

    setInputs(prevInputs => ({ ...prevInputs, [name]:value}));
    

    这很管用。现在我想删除扩展运算符以最大限度地提高跨浏览器兼容性。

    不幸的是,当我尝试使用其他方法将值更改更新为state对象中的属性时,会出现错误:

    组件正在将文本类型的受控输入更改为不受控制。输入元件不应从受控切换到非受控

    我理解此错误消息的含义,我无法理解的是,与spread运算符相比,我的对象更新有什么不同,下面是我尝试替换spread运算符的方法:

    if (value) {
        //try to update state with value that is not undefined
        setInputs(prevInputs => Object.assign({}, prevInputs)[name] = value);
    
        //another try to update state with value that is not undefined
        setInputs(prevInputs => prevInputs[name] = value);
    }
    

    我不明白这是怎么回事,Spread操作符正在创建一个新对象:

    const originalObj = {
        name: '',
    };
    const spread = {...originalObj};
    console.log('is originalObj === spread', originalObj === spread); //no they are not
    

    我的对象如何。指定替换排列的方式而不是模仿排列运算符对象的创建来关闭排列?

    2 回复  |  直到 6 年前
        1
  •  1
  •   CertainPerformance    6 年前

    要模拟排列并为对象指定新特性,需要

    (1)创建原始对象的浅层副本

    (2)为复制的对象指定一个新值

    (3)返回复制的对象

    当你这样做的时候

    setInputs(prevInputs => Object.assign({}, prevInputs)[name] = value);
    

    你在做一个浅显的拷贝,但是 返回任务 ,因此返回值是赋值的值,而不是复制的对象。上述代码相当于

    setInputs(prevInputs => value);
    

    最好避免在表达式中使用赋值-它们几乎不是你想要的。

    setInputs(prevInputs => prevInputs[name] = value);
    

    你做的事情有点相似:你在改变现有的 prevInputs 对象,并返回 value 是的。相当于

    setInputs(prevInputs => {
      prevInputs[name] = value;
      return value;
    });
    

    要实现浅复制,请在复制的对象上设置一个值,然后返回该值,请执行以下操作:

    setInputs(prevInputs => {
      const newInputs = Object.assign({}, prevInputs); // Shallow copy
      newInputs[name] = value; // Assign new value
      return newInputs; // Return copied object
    });
    

    或者,相当于:

    setInputs(prevInputs => Object.assign({}, prevInputs, {[name]: value }));
    

    上面的工作是因为 Object.assign 返回新对象(第一个参数)。

    请记住,这样可以避免对象扩展语法(即ES2018),从而使代码与ES2015兼容。要使代码与es5(es2009)兼容,需要做更多的工作。不管怎样,为了使代码兼容,最好使用 Babel 为了自动处理它-这使您的源文件保持良好的可读性,同时允许过时的浏览器理解透明代码。

        2
  •  1
  •   Cecil John Tantay    6 年前

    根据babel本身,spread操作符看起来与浏览器兼容。

    enter image description here