0

How can you change the status as an object? I did it this way, but I don't think it's right, because in compiling it gives a setState warn. I would like to understand how to change a state whose value is an object.


class Animation extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            step    : step,
            ledge   :{zoom:1, display:"flex"},
            map     :{zoom:0, x:0, y:0, rotate:0},
        };
    }
    StepForward = () => {
        step = step + 1;
        //STEP 1
        if(step === 1){
            this.setState({ 
                ...this.state.ledge.zoom = this.state.ledge.zoom - 1, 
                ...this.state.ledge.display = "none"
             });   
        }
    }
    StepBack = () => {
        step = step - 1;
        if(step < 0 ){
            this.setState({step:step})
            step = -1
        }
        //STEP 0
        if(step === 0){
            this.setState({ 
                ...this.state.ledge.zoom = this.state.ledge.zoom + 1, 
                ...this.state.ledge.display = "flex",});
        }
    }
    render() {
        return (
            <div id="content_animation">
               <div id="step back" class="command" onClick={this.StepBack}>
                   <img class="arrow" src="img/arrow_b.svg" alt="back"/>
               </div>
               <div id="animation">
                   <AnimationStep 
                    step = {this.state.step}
                    ledge={this.state.ledge}
                    map={this.state.map}/>
               </div>
               <div id="step forward" class="command" onClick={this.StepForward}>
                  <img class="arrow" src="img/arrow_f.svg" alt="forward"/>        
               </div>
           </div>
        )
    }
}
export default Animation

when I compile it gives me the error that you see below but if you insert a comment above the line of code "wrong", then it works and compiles correctly ...

Compiled with warnings.

Do not mutate state directly. Use setState()  react/no-direct-mutation-state
Do not mutate state directly. Use setState()  react/no-direct-mutation-state
Do not mutate state directly. Use setState()  react/no-direct-mutation-state
Do not mutate state directly. Use setState()  react/no-direct-mutation-state

Search for the keywords to learn more about each warning.
To ignore, add //eslint-disable-next-line to the line before.
  • Possible duplicate of [Do not mutate state directly, Use setState() react/no-direct-mutation-state in React JS](https://stackoverflow.com/questions/43691823/do-not-mutate-state-directly-use-setstate-react-no-direct-mutation-state-in-r) – Emile Bergeron Aug 16 '19 at 20:08

4 Answers4

3

As the error clearly states, you're mutating your state directly, which will cause bugs along the way. You can set state without mutating it like this:

this.setState(state => ({
  ...state,
  ledge: {
    ...state.ledge,
    zoom: state.ledge.zoom - 1,
    display: 'none'
  }
}));

Useful links:

Mutating state - https://daveceddia.com/why-not-modify-react-state-directly/

Functional setState - https://www.freecodecamp.org/news/functional-setstate-is-the-future-of-react-374f30401b6b/

Object spreading - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals

Clarity
  • 10,730
  • 2
  • 25
  • 35
-1

The problem is with your setState calls and how you're setting those values:

this.setState({
  ledge: {
    zoom: this.state.ledge.zoom - 1,
    display: 'none'
  }
});
Josh Rutherford
  • 2,683
  • 1
  • 16
  • 20
  • 2
    Clarity's answer is the preferred way to go as passing a function to setState is better when mutating the state depending on its previous values. – Victor Levasseur Aug 16 '19 at 15:59
  • 2
    Also, I'm pretty sure that React won't merge nested properties automatically, resulting in a completely replaced `ledge` object. – Emile Bergeron Aug 16 '19 at 16:04
-1

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

You perhaps would love to check difference between mutable and immutable aswell.

What you should do in this case you could use spread operator :

        this.setState(prevState => ({
        ledge: {                   // object that we want to update
            ...prevState.ledge,    // keep all other key-value pairs
            zoom: this.state.ledge.zoom -1       // update the value of specific key
        }
    }))
Damian Busz
  • 1,693
  • 1
  • 10
  • 22
-1

When you use this.setState, you don't have to explicitly say this.state in the assignments within it. I haven't been able to set the inner class the way you or the other answers have done. I usually do another step to successfully set the state.

this.setState({ 
    ...this.state.ledge.zoom = this.state.ledge.zoom + 1, 
    ...this.state.ledge.display = "flex",});

becomes:

var tempLedge = this.state.ledge;
tempLedge.zoom = this.state.ledge.zoom + 1;
tempLedge.display = "flex";

this.setState({ledge = tempLedge});

Related, but not a dupe:
What is the correct way of setting state variables in Reactjs and what is the difference between these approaches?

Also, check out this link for more info: State and Lifecycle

Edgar
  • 6,022
  • 8
  • 33
  • 66
computercarguy
  • 2,173
  • 1
  • 13
  • 27