2

I have the following state.

state = {
  friends: {
    nickNames: ['Polly', 'P', 'Pau'],
    ... here more k:v
    },
  }
}

And I want to update nickNames array with a value coming from an uncontrolled form through a method in my class. However, I'm having issues at the time of determine if I am setting the state properly without mutating it.

I am doing the following

updateArray = (nickName) => {

  const tempDeepCopy = {
    ...this.state,
    friends: {
      ...this.state.friends,
      nickNames: [...this.state.friends.nickNames]
    }
  }

  tempDeepCopy.friends.nickNames.push(nickName)

  this.setState({
    friends: 
    {
      nickNames: tempDeepCopy.friends.nickNames
    }
  })

}

Is this the proper way of doing it? If so, is it also the most efficient given the state? I am trying to avoid helper libraries to learn how to make deep copies.

I will appreciate help since Im trying to learn immutability and it is a concept that is taking me a lot of effort.

Peter
  • 2,004
  • 2
  • 24
  • 57
  • If you use [hooks](https://reactjs.org/docs/hooks-intro.html), specifically the `setState()` hook, you can create multiple state variables, which can make it a lot easier to update the state—you don't always have to merge changes into a single giant state object. – Matt Browne Oct 04 '19 at 01:42

4 Answers4

4

setState() in class components does shallow merge.

So you could just ignore other "parent" keys and focus only on friends.

You can also simplify it like:

this.setState({
  friends: { // only focus on friends
    ...this.state.friends, // do not ignore other friend k:v pairs
    nicknames: [
      ...this.state.friends.nicknames,
      nickName
    ]
  }
})
Joseph D.
  • 11,804
  • 3
  • 34
  • 67
2

Why not just;

updateArray = (nickName) => {

  const updatedNickNames = [...this.state.friends.nickNames, nickName];

  this.setState({
    friends: {
      ...this.state.friends,
      nickNames: updatedNickNames
    }
  });

}

Because nickNames is just a array of strings, you can copy it with the spread operator. Also, with setState you can change a specific part of your state, in your case you only have to worry about the friends part.

Miller
  • 311
  • 1
  • 5
0

You can just use

this.setState({
    friends: 
    {
      nickNames: [...this.state.friends.nickNames, nickName]
    }
  })

State should be only modified through the setState function because if you modify it directly you could break the React component lyfecycle.

mordecai
  • 55
  • 9
0

It is a correct way to do that. The thing is you must never change the state directly. That is it.

I might give a more concise code

state = {
  friends: {
    nickNames: ['Polly', 'P', 'Pau'],
    ... here more k:v
    },
  }
}

updateArray = (nickName) => {
  this.setState(prevState => ({
    ...prevState,
    friends: 
    {
        ...prevState.friends,
        nickNames: [...prevState.friends.nickNames, nickname]    
    }
  }))

}

As long as you do not change the state directly, any way will do through setState()

  • prevState is used to monitor the previous state. Since setState is asynchronous, it is a good practice to make sure the previous function is done. – alfredo ryelcius Oct 04 '19 at 01:45