1

I have state like this -

  state = {
    modal: {
      status: {
        visible: true
      }
    }
  };

and i tried this

handleShow = e => {
    let newState = this.state.modal;
    newState.status.visible = false;
    this.setState({ modal: newState });
  };

First time it makes true->false but i want toggle like(true to false and false to true) when i click.

Here is complete Sample code

class App extends React.Component {
  state = {
    modal: { status: { visible: true } }
  };
  handleShow = e => {
    let newState = this.state.modal;
    newState.status.visible = false;
    this.setState({ modal: newState });
  };
  render() {
    return (
      <>
        <div>
          {this.state.modal.status.visible ? (
            <div style={showStyle}>"it's showing"</div>
          ) : (
            "It's Hidden"
          )}
        </div>
        <button onClick={this.handleShow}>
          {this.state.modal.status.visible ? "Hide" : "Show"}
        </button>
      </>
    );
  }
}
const showStyle={
    backgroundColor: 'coral',
    height: '100px'
}

Can anybody help me with this?. Thanks.

5 Answers 5

2

there is a few things going on here. You are technically setting a reference to the state object when you do let newState = this.state.modal;, so you're not actually creating "new" state. then when you set to false you're just setting the original state object to false and it never toggles back as there is no re render/logic to make it re render and change the state back to false. The most straight forward approach you could try is

handleShow = e => {
  this.setState({ modal: { status: { visible: !this.state.modal.status.visible } } });
};

as every time you click it you will be setting the boolean to whatever it was not the last time, essentially doing the toggle I think you're looking for. Look into state and how it is immutable. You should be making a copy of the state and returning a new object technically

// if you were to go more towards the pattern you had going already
handleShow = e => {
  let newState = { ...this.state, modal: { status: { visible: this.state.modal.status.visible } } };
  this.setState(newState);
}

this spread operator is essentially spreading all the properties from the original state into a new object, then you change the value you want on the newState, then you set the state to that new object which contains all the other parts of the state not modified as well as what you want modified.

there is also something to be said about modifying state the relies on previous state and react setState method being asynchronous. the more solid approach to set state using previous state if you're not using spread would be to pass a callback function to setState instead of an object with the current state as a variable

this.setState(currentState => {
  return { modal: { status: { visible: !currentState.modal.status.visible } } }
});
Sign up to request clarification or add additional context in comments.

1 Comment

as an aside there are many ways to handle this scenario and the code could be reduced with destructuring and what not, but I wanted to try to stay on point and use the full variable names to make it clear what was going on
1

Instead of this newState.status.visible = false; you can try newState.status.visible = !newState.status.visible;

Comments

1

Write newState.status.visible = !newState.status.visible; instead to make it false

 handleShow = e => {
    let newState = this.state.modal;
    newState.status.visible = !newState.status.visible;
    this.setState({ modal: newState });
  };

Comments

1

It is a bad idea to mutate state. The best practice is to create a new copy of the object and update it instead and then update the state. The ... spread operator creates shallow copy of the object. So you would need to spread the properties so that we are keeping it untouched ( not a big deal here as each nesting has only one property, but would break when there is more than 1 property )

handleShow = e => {
    const  { 
       modal
    } = this.state;

    const updatedState = {
       ...modal,
       status: {
          ...modal.status,
          status: {
             visible: !modal.status.visible
          }
       }
    }

    this.setState(updatedState);
  };

Comments

0

Changing State should be coming only from setState function.

by doing const x = obj; you are making x === obj (both point to the same pointer). therefore changing x will change obj aswell. you should make a copy of the state you want to change first, and then assign the changed copy to the state. With ES6 you can copy an object with the spread (...) Good Luck!

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.