Can the value of “this.state.visibility" be changed?

I’m confused about the line of "because state updates may be asynchronous, we can’t rely on the previous value of this.state or this.props", is it saying that the value of “this.state” or “this.props” can’t be upgraded, they are initials? Instead, “state.xxx” or “props.xxx” can be updated. So we use ‘state.visibility’ rather than ‘this.state.visibility’,right?
But the line of “if (this.state.visibility)” in the render part tells me that this.state.visibility can be equal to true or false, it shows that the value of it can be changed, so anybody can tell me what the problem is, I hope I’ve made me clear, thanks!

Question:
MyComponent has a visibility property which is initialized to false . The render method returns one view if the value of visibility is true, and a different view if it is false.

Currently, there is no way of updating the visibility property in the component’s state . The value should toggle back and forth between true and false. There is a click handler on the button which triggers a class method called toggleVisibility() . Pass a function to setState to define this method so that the state of visibility toggles to the opposite value when the method is called. If visibility is false , the method sets it to true , and vice versa.

Finally, click the button to see the conditional rendering of the component based on its state .

Hint: Don’t forget to bind the this keyword to the method in the constructor !
Your code so far


class MyComponent extends React.Component {
constructor(props) {
  super(props);
  this.state = {
    visibility: false
  };
  // Change code below this line
  this.toggleVisibility = this.toggleVisibility.bind(this);
  // Change code above this line
}
// Change code below this line
toggleVisibility() {
  this.setState((state) => {
    if (state.visibility === true) {
      return {visibility: false}
    } else {
      return {visibility: true}
    }
  });
}

// Change code above this line
render() {
  if (this.state.visibility) {
    return (
      <div>
        <button onClick={this.toggleVisibility}>Click Me</button>
        <h1>Now you see me!</h1>
      </div>
    );
  } else {
    return (
      <div>
        <button onClick={this.toggleVisibility}>Click Me</button>
      </div>
    );
  }
}
}
  **Your browser information:**

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36

Challenge: Use State to Toggle an Element

Link to the challenge:

is it saying that the value of “this.state” or “this.props” can’t be upgraded, they are initials?

No.

The original text:

However, state updates may be asynchronous - this means React may batch multiple setState() calls into a single update. This means you can’t rely on the previous value of this.state or this.props when calculating the next value.

What it is saying is that when you update state, you don’t know when it is going to happen. It is asynchronous, meaning it will happen at some point in the future. It will be probably be less than a millisecond, but the code is not going to wait. So, if I have:

// assume that this.state.num === 5
this.setState({ num: this.state.num + 3 })
this.setState({ num: this.state.num * 2 })

What the text is saying is that when the second setState is run, you don’t know that the first setState has finished running. You don’t know what the this.state.num will be inside the second setState call. We assume it will be 8, but it could also be 5. setState just says “at some point in the near future, run this”.

There are a few ways to deal with this. This lesson is teaching you one - use a callback instead.

Currently, there is no way of updating the visibility property in the component’s state .

As I’ve just explained, that is not true. You can change it all you want.

1 Like

Sorry, I didn’t make it clear to you, what I want to say is why we use (state.visibility) in toggleVisibility(){}, and use “this.state.visibility” in render() part, thanks

toggleVisibility() {
  this.setState((state) => {
    if (state.visibility === true) {
      return {visibility: false}
    } else {
      return {visibility: true}
    }
  });
}

Because this.state.visibility would refer to the component state. Remember, we can’t be sure that that has been updated yet if there was a previous call to setState. So, the callback function gets called with a parameter that is guaranteed to be “up to date”. Here, we’ve chosen to call it “state”. We don’t have to:

toggleVisibility() {
  this.setState((upToDateState) => {
    if (upToDateState.visibility === true) {
      return {visibility: false}
    } else {
      return {visibility: true}
    }
  });
}

or even

toggleVisibility() {
  this.setState((elephantPajamas) => {
    if (elephantPajamas.visibility === true) {
      return {visibility: false}
    } else {
      return {visibility: true}
    }
  });
}

I would also point out that this would do the same thing:

toggleVisibility() {
  this.setState(state => ({visibility: !state.visibility});
}

So what you said its “this.state.visibility” can’t guarantee the most current value, because state updates may be asynchronous, “this.state.visibility” maybe equal to the previous value rather than the current value. “state.visibility” can guarantee the most current value, because it takes all situations in consideration as a parameter of callback function, right?

So if we modify the code to
this.setState({ num: state.num + 3 })
this.setState({ num: state.num * 2 })
is OK? Why?

Yes. I would just reiterate that calling that parameter “state” is arbitrary. It’s just a parameter that’s being passed in. React guarantees that that will represent the most recent version of state, after all updates.

There may be situations where you don’t care and you can pass an object. I worry about it if the new state will be based on the old state or if there is a risk of rapid fire calls.

1 Like

No, because “state” is not defined. We would need a function there.

this.setState(foo => ({ num: foo.num + 3 }))
this.setState(bar => ({ num: bar.num * 2 }))

Now, you could change both of those variable names to “state” because that is the convention. But you don’t have to. It is not taking its value directly from this.state. It is being passed that reference by the function as a parameter.

Yes, I knows few about the slight difference in React, but I agree with you that slight difference makes big difference in result.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.