Use State to Toggle an Element: more efficient answer?

Is there a more efficient way to write this answer than by using a long if statement? I’ve tried playing around with ! and using arrow forms but can’t seem to get anything else to work. It just seems like a lot of writing for a relatively simple task.

Yes, the ! is definitely the way to go. You could write two setStates, using and if to switch between them, but that is not necessary.

You want to set that visibility property to the opposite of what this.state.visibility currently is. That is where the ! comes in and allows you to do it in one line (within the toggleVisibility method).

You can of course send setState a simple object. That is the “old” way. I don’t know if they have taught you the new way yet, but you mention “arrow forms” which might mean a fat arrow function. There is a functional setState which is considered “better” especially because the new state is dependent on the old state. But that also would use the !, but would return the object out of a small function. That can also be a one line solution. But if they haven’t taught you the functional setState then I wouldn’t worry about it yet. Once you understand the basics of setState and how callback functions work, it’s an easy transition.

What have you tried?

Sorry for the delay in response, holidays got to me.

This is the ‘long form’ if answer that passes:

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

This was a hopeful attempt:

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

then realized that it probably couldn’t ‘see’ the visibility I was assigning. This finally passed:

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

I’m not sure what your last paragraph means, tbh :sweat_smile:I supposed I’ll look up function setStates later. This second solution is clearly more efficient than my original answer, but would you improve upon it?

Cool. You found a working solution. That is probably what FCC had in mind. That is the “old” way of using setState and was probably the preferred way when FCC wrote it. You are calling setState with a plain object. You are calling it with:

{ visibility: !this.state.visibility }

That is probably fine for now. The issue (and you can google “react functional setState” for more explanation) is that you are referring to state while you are trying to change it. What if state changes before setState (which is asynchronous) runs? What if you make several calls to setState in a short amount of time and they don’t execute in the order you expect? In this case it may be a moot point, but it can cause errors in other cases. Because of this, the “new” way is to pass it a function that accepts the old state and returns the object. For this, it would look like:

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

or if we wanted to break that up, we could use:

const toggleVisibility = state => ({
  visibility: !state.visibility,
});

this.setState(toggleVisibility);

Instead of relying on the state on this it is passing in the correct version of state and making sure that if setStates are batched or delayed, they will all run in the correct order. There are other advantages in functional programming paradigms and testability.

Now, it turns out to not be an issue here, but I thought I’d mention it in case it was.

If this is too much for you to worry about at this point, then just ignore it for now. There is plenty of time to learn it later and there are plenty of things to learn before that. And this may not be an issue in your apps for some time to come.

2 Likes

Thanks for the thorough explanation! I’ll try to keep that in mind moving forward.