如何在React状态下正确更新对象或数组

时间:2019-06-26 09:49:03

标签: javascript reactjs react-native state

假设这是我的状态:

state={
  user:{
    name: 'Joe',
    condition:{
      isPrivate: true,
      premium: false
    }
  }
}

这是我可以用来更新user的方法:

updateUser = (property, value)=>{
  // firstway. probably not a good one
  let user = this.state.user; 
  user[property] = value;
  this.setState({user})

  // second way. probably the best way
  let user = JSON.parse(JSON.stringify(this.state.user))
  user[property] = value;
  this.setState({user})
}

尽管我知道直接修改状态不是一个好习惯,但是到目前为止,我从两个方法中得到的结果都是相同的,并且没有副作用。 因此,为什么要采取这个额外的步骤来复制状态,然后在复制的对象上对其进行修改,而这却减慢了操作的速度(但是非常少)! 那么哪一个会更快?在反应的情况下,第一种方法的副作用是什么?最后每种方法的优缺点是什么?

2 个答案:

答案 0 :(得分:0)

基本思想是避免变异对象,而是创建新对象

咒语意味着您应该避免直接更改内存中具有的javascript对象的变量,而应该每次都创建一个新对象。

您可以使用ES6 spread operator来克隆对象。使用散布运算符,您还可以更新克隆的属性,以便对对象属性执行所需的更新。

这是您需要的代码:

updateUser = (property, value) => {
  const user = {...this.state.user, [property]: value}; // gets a clone of the current user and update its properties
  this.setState({ user });
}

上面语法中的三个点不是错字,它们是上述的ES6扩展运算符

根据我的知识(我很新来做出反应),基本上有三个避免直接状态突变的原因:

    每次
  • 重新计算新状态要比尝试更新现有状态简单。从概念和编码的角度讲,更简单的意思是更简单。每次避免出现任何副作用都创建一个新对象将简化您的代码并减少错误。

  • 您不能确定组件及其子组件如何使用给定状态。该状态由组件使用,并且可以通过prop传递给其子组件。如果仅对组件进行独立推理,那么您将不知道子组件如何使用该状态。通过更改对象的属性来改变其在内存中的状态会发生什么?回复是谁知道。您可能会产生一系列副作用,而且更重要的是,如果仅对组件进行推理,则无法确定会出现哪种副作用。这实际上取决于组件层次结构的构成方式。关于副作用的推理总是一团糟,应对它们的风险太大,并且一种更好的方法是尝试避免它们。

  • 设计了
  • react and react dom,可以通过遵循功能方法的最佳实践(无副作用且无直接状态突变)来有效地更新状态变化时的浏览器DOM。这意味着,如果您按照建议的方式使用react,则react本身将有更好的时间来计算要应用于DOM的修改,以便重绘组件,然后您的应用程序将表现更好。

答案 1 :(得分:0)

作为对您更新状态的第一种方法的回应,您获得了对嵌套在状态中的对象的引用。

 System.out.println(">Mobiles,Computers");
    System.out.println(">TV,Appliances,Electronics");
    System.out.println(">Men's Fashion");
    System.out.println(">Women's Fashion");
    System.out.println(">Home accessories");
    System.out.println("do you want to choose your product from above catagories or not \n enter y/n (REPLY IN SMALL LETTERS");
    c1=(char)br.read();
    while(c1 != 'n')
    {
    System.out.println("-----------------------------------------------------------------------");
    System.out.println("Enter your choice");
    System.out.println("Press 1: Mobiles,Laptops");
    System.out.println("Press 2: TV,Appliances,Electronics");
    System.out.println("Press 3: Men's Fashion");
    System.out.println("Press 4: Women's Fashion ");
    System.out.println("Press 5: Home accessories");
    System.out.println("-----------------------------------------------------------------------");
    int choice=Integer.parseInt(br.readLine()); 
    switch(choice)
    { 

在此块中,您已经更新了状态,因此您实际上正在执行副作用。对setState()的调用仅反映了UI中的那些更改(即,组件的重新呈现)。

不直接修改状态的原因可能是该状态中的一些意外更新。例如,如果您要通过修改this.state中的某些数据并将其作为请求的主体发送(请注意,您不希望这些更新反映在UI中)来进行api调用,请修改就像您在方法1中所做的那样,直接导致状态改变,可能会导致状态发生一些不必要的更改,随后对setState()的调用可能会向应用程序用户暴露一些不必要的更改。

但是在您的示例中,可以使用其中任何一种方法,但这可能不是一个好习惯。

希望这会有所帮助!