在不使用传播运算符的情况下正确更新React.js状态下的对象

时间:2019-10-14 00:09:31

标签: javascript reactjs

根据Visual Studio或ReSharper Intellisense,散布运算符...是实验级别的功能,我正在使用ECMAScript 2015: enter image description here

我正在使用Babel,并且在已编译的源代码中看到了传播算子: enter image description here

因此,我尝试用Object.assign替换用于在React状态下的对象进行更新的散布运算符功能。

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

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

这很好。现在,我想删除散布运算符,以最大程度地实现跨浏览器的兼容性。

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

  

一个组件将文本类型的受控输入更改为不受控制。输入元素不应从受控切换为不受控制

我理解此错误消息的含义,与扩展运算符相比,我无法理解的是对象更新的不同之处,这是我尝试替换扩展运算符的方式:

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

我不明白这里发生了什么,散布运算符正在创建一个新对象:

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

我的Object.assign替换价差的方式如何不会像价差运算符对象的创建那样结束?

2 个答案:

答案 0 :(得分:1)

要模拟传播并将新属性分配给对象,您需要

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

(2)为该复制对象分配一个新值

(3)返回复制的对象

这样做的时候

public static class Class1
{
    // simulate reading lines from file
    public static List<String> SAO_Num = new List<String>() {
        "test1",
        "test2",
        "test3",
        "test4",
        "test5",
        "test6",
        "test7",
        "test8",
        "test9",
        "test10"
    };

    public static int countSAO = SAO_Num?.Count ?? 0;
}

public class Class2
{
    ...
    button.Text = Class1.countSAO.ToString();
    ...
}

您要创建一个浅表副本,但随后您要返回赋值,因此返回值是赋值的值,而不是复制的对象。上面的代码等效于

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 })); 返回了新对象(第一个参数)。

请记住,这避免了对象传播语法(即ES2018),从而导致代码与ES2015兼容。为了使代码与ES5(ES2009)兼容,需要做很多工作。无论哪种方式,为了使您的代码兼容,最好使用Babel自动处理它-这样可以使源文件保持美观和可读性,同时允许过时的浏览器了解已转译的代码。

答案 1 :(得分:1)

根据babel本身,看来传播算子与浏览器兼容。

enter image description here