简体   繁体   中英

React shouldComponentUpdate detect change

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.

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

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]}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM