0

I couldn't find any similar question, I don't know what could be happening there, (and maybe could be something stupid) but I haven't found any clue about what could be happening.

I have this array:

const superVillains = [
  { value: '1', label: 'Thanos' },
  { value: '2', label: 'The Joker' },
  { value: '3', label: 'Ultron', disabled: true },
  { value: '4', label: 'The Riddler' },
  { value: '5', label: 'Lex Luthor' },
  { value: '6', label: 'Green Goblin' },
  { value: '7', label: 'Bain', disabled: true },
  { value: '8', label: 'The Penguin' },
  { value: '9', label: 'Doctor Octopus' },
  { value: '10', label: 'Poison Ivy' },
  { value: '11', label: 'Magneto' },
  { value: '12', label: 'Mr. Glass' },
  { value: '13', label: 'General Zod' },
  { value: '14', label: 'Red Skull', disabled: true },
  { value: '15', label: 'Baron Von Zemo' }
];

I copied this array into another called optionsState in a react state

const [optionsState, setOptionsState] = useState(superVillains);

and applied the following operations:

const index = 0; 
optionsState[index]['selected'] = true; 
console.log(optionsState[index]['selected']);
console.log(optionsState[index]);
console.log(optionsState);

This is the result in console:

Console redult

In the first console output it seems that the selected value is true as it should, the same for the second console output, but without changing nothing in the code the third console output shows that the selected value is false.

the question is: Why does the selected value apparently changes without applying any operations on it (besides a console log statement)?

If a place another

console.log(optionsState[index]);

after the last console log it will show the same as before:

{value: "1", label: "Thanos", selected: true}

so I don't know if it is an issue with the browser or an issue with the react states or an issue with me.

Any ideas on this?

Fabian Merchan
  • 943
  • 8
  • 15
  • what are the values of option , element ? – Renaldo Balaj Nov 29 '19 at 16:39
  • just do a fully running demo with https://stackblitz.com/fork/react or explain every variable – Renaldo Balaj Nov 29 '19 at 16:40
  • Works as expected with the code provided... Do not have the same issue... – SakoBu Nov 29 '19 at 16:46
  • @RenaldoBalaj option and element are not relevant, I edited to make that clear. Also I will give a try to the tool you posted, thank you! – Fabian Merchan Nov 29 '19 at 16:48
  • 1
    i gave you the answer, careful of other answers they are mutating the object – Renaldo Balaj Nov 29 '19 at 16:52
  • for more questions, comment at the answer – Renaldo Balaj Nov 29 '19 at 16:53
  • Does this answer your question? [Whats the best way to update an object in an array in ReactJS?](https://stackoverflow.com/questions/28121272/whats-the-best-way-to-update-an-object-in-an-array-in-reactjs) – Emile Bergeron Nov 29 '19 at 17:03
  • Hi everyone, I was not trying to update the state, I mean, eventually I will update the state and for sure I will do it as you suggested, but in this case taking a look to the variable not as updating the state but just as a single array it shouldn't change the value? as far as I know if you change a value in a state it will change but you shouldn't do it like that because it will be changed when the setOptionsState function is called. but that's another concern. My question was not about how to change the state (I know there a lot of example about how to do this) – Fabian Merchan Nov 29 '19 at 17:11
  • @FabianMerchan you were mutating the state, you should never do stateX = 'x' , always setStateX('x'). Because you did **that equal thing**, all of this nonsense happened, try to update the state in the same way as in my answer :) – Renaldo Balaj Nov 29 '19 at 17:20
  • [Why can't I directly modify a component's state, really?](https://stackoverflow.com/q/37755997/1218980) – Emile Bergeron Nov 29 '19 at 17:34

4 Answers4

2

Now that you edited your question, I get it :)

You are mutating your state, and react is based in immutability (google for more), a quick fix would be :

setOptionsState(prevState => {
  const oldOptions = [...prevState.optionsState];
  oldOptions[index] = { ...oldOptions[index] , selected: true };
  return { oldOptions };
})
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Renaldo Balaj
  • 2,390
  • 11
  • 23
  • 1
    It's spelled *immutability* and no need for caps. – Clarity Nov 29 '19 at 16:58
  • if you want to highlight the word like that then why not. – Clarity Nov 29 '19 at 17:12
  • https://stackblitz.com/edit/react-mjftz7 take a look ok this I tried to do same and in this fiddle it works as expected, it changes the selected value in all the console log statements (even when I know that you should not change the state like that) I am starting to think that this is an issue related only to my project and not as a general question. – Fabian Merchan Nov 29 '19 at 17:27
  • it may change it correctly in console.logs , but is it stable? nah Try printing that array in the screen with .map , and when you change it in your way the printed array won't change. – Renaldo Balaj Nov 29 '19 at 17:31
  • 2
    @RenaldoBalaj There are typos in your code example. `const oldOptions =[...prevState.optionsState];` since it's an array. – Emile Bergeron Nov 29 '19 at 17:33
  • I tried your answer (and I know that it is the correct way to update the state) but still doesn't work. – Fabian Merchan Nov 29 '19 at 17:33
1
optionsState[index]['selected'] = true; 

You should not mutate state like this. If you want to add a new attribute to the state, you should do it using the function provided, in your case it is going to be setOptionsState. The easiest way to achieve this should be something like this:

setOptionsState(prevState => {
  const oldOptions = [...prevState.optionsState];
  oldOptions[index] = { ...oldOptions[index], selected: true };
  return { oldOptions };
})

Please try this approach and see if it's any different (I hope so!)

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Konstantin
  • 1,390
  • 6
  • 18
1

As already said, you're directly mutating the state, which is a bad idea in React. To properly update the state use functional form of setState plus map:

const index = 0;

setOptionsState(options => {
  return options.map((option, i) => {
    if (index === i) {
      return {
        ...option,
        selected: true
      }
    }
    return option;
  })
})
Clarity
  • 10,730
  • 2
  • 25
  • 35
0

if you want to change the value of optionsState use setOptionsState because the state value is updated after the refresh if you dont use setOptionsState.