1

I must be doing something dumb here, but after a day of trying to figure it out, I am turning here...

I have a dropdown menu for each element of an array val which I save in the Component state:

class C extends Component {

    state = { val : [ 1,2,3,4] }
    ...

}

where a change in each of the dropdown entries triggers this callback:

  onChanged = (event, index) => {
    console.log("val changed");
    this.setState(state => {
      const val = state.val;
      val[index] = event.target.value;
      return { val: val };
    });
  };

Now the issue is that I can't figure out how to detect this change in shouldComponentUpdate. Specifically, when I change one of the dropdown options, I see val changed being logged. However, in the shouldComponentUpdate method, the nextState and this.state always contain the same values (and appear to be identical on comparison). So there is no way for me to detect a change in shouldComponentUpdate. Here is the exact code I am using:

shouldComponentUpdate(nextProps, nextState) {

    console.log(
      "shouldComponentUpdate",
      nextProps.val,
      this.state.val,
      nextState.val,
      this.state.val === nextState.val
    );
    return false;
}

Before a change in one of the dropdown options, this logs something like

shouldComponentUpdate, undefined, [1, 2, 3, 4], [1, 2, 3, 4], true

If I change the first dropdown from 1 to 9, then I see

shouldComponentUpdate, undefined, [9, 2, 3, 4], [9, 2, 3, 4], true

I expected that immediately after the change I would see

shouldComponentUpdate, undefined, [1, 2, 3, 4], [9, 2, 3, 4], true

Please tell me how I can detect a change in shouldComponentUpdate or what idiom I should be using.

EDIT:

It was suggested that I slice the value array in the onChanged callback, that is, change to callback to:

  onChanged = (event, index) => {
    console.log("val changed");
    this.setState(state => {
      const val = state.val.slice();
      val[index] = event.target.value;
      return { val: val };
    });
  };

That did not fix the issue. Here is the console log before and after a change:

shouldComponentUpdate undefined (4) [1, 2, 3, 4] (4) [1, 2, 3, 4] true
val changed
shouldComponentUpdate undefined (4) [9, 2, 3, 4] (4) [9, 2, 3, 4] true 

EDIT:

Crikeys I am dumb. There was a dumb return statement that was getting hit. I totally missed it. I am accepting the answer below since they are correct as the problem was stated.

2 Answers 2

2

That is because you are mutating the array and re use it.

Change const val = state.val; to either

const val = [...state.val];

or

const val = state.val.slice();

to create a new array

Sign up to request clarification or add additional context in comments.

1 Comment

I am pretty sure I tried slicing already and that wasn't working. Let me check again
0

JS arrays are passed by reference and not pass by value.
when you are doing const val = state.val; and val[index] = event.target.value; it is changing the state variable before setState.

example:

var a = {x: [1,2,3]}
var b = a.x
b[0] = 5 // b = [5, 2, 3] and a = {x: [5,2,3]}

You can use slice or destructuring to solve your problem.

//Slice
const val = state.val.slice()
//Destructure
const val = [...state.val]

In the above example:

var a = {x: [1,2,3]}
var b = [...a.x]
var c = a.x.slice()
b[0] = 5     //b = [5, 2, 3] and a = {x: [1,2,3]}
c[0] = 6    //b = [6, 2, 3] and a = {x: [1,2,3]}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.