Ufuk Ozdogan
Ufuk Ozdogan

Reputation: 13

setState One State of an Object in a Mapping Function

I've been dealing with this issue for two days. Couldn't find a solution online and at this point I think I'm doing something wrong.

So the point of this app is to click the button and drop an apple. Clicking the button changes tree's state and classname in the component causing it to shake. And Sass animation does the rest. But I can't change one apple's classname. And therefore, cannot animate one apple. It just changes all of them I think and they kinda overlap on top of each other. Which is not what I wanted.

Don't know if I'm handling the process wrong but here's the code for app.js:

class App extends Component {

  constructor(props){
    super(props);
    this.state = {
      apples: [],
      treeState: ''
    }
  }

  componentWillMount(){
    this.setState(
      {
        apples: [
      {
        id: '1',
        status: 'present'
      },
      {
        id: '2',
        status: 'present'
      },
      {
        id: '3',
        status: 'present'
      }
    ],
  treeState: 'stagnant'});
  }

  render() {
    return (
      <div className="App">        
        <div className="App-header">
        <img onClick={this.shakeTree.bind(this)} className="grab" alt="grab"/>
          <Apples apples={this.state.apples}/>
          <Tree treeState ={this.state.treeState}/>              
        </div>
      </div>
    );
  }

  shakeTree() {
    var css = (this.state.treeState === "stagnant") ? "shaking" : "stagnant";
    this.setState({"treeState":css}); 
    this.dropApples();
}

  dropApples(){
      let apple;
      var random = 2;
      if(this.state.apples){
        apple = this.state.apples.map(applemon => {   
          if(applemon.id==random){
            this.setState(
              {
                apples: [
              {
                id: random, 
                status: 'falling'
              }
            ]});
          }              
        });  
    }
  }  
}

export default App;

What I want is to change one of the apples' status to 'falling' without affecting the others. For example, get the apple with id of 2 and change it's status to 'falling'.

Can you please walk through me how or point me some exact resources about how it's done.

Upvotes: 0

Views: 1261

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281894

You aren't updating the state correctly. You should return the entire updated object to setState

dropApples(){
      let apple;
      var random = 2;
      if(this.state.apples){
        this.setState(prevState => ({
            apples: prevState.apples.map(apple => {
                if (apple.id == random) return {...apple, status: 'falling'}
                return apple
            })
        })) 
    }
} 

Upvotes: 1

gillyhl
gillyhl

Reputation: 475

on dropApples, do this to set status to falling for the random apple

this.setState({
    apples: this.state.apples.map(
        apple => apple.id === random ? { ...apple, status: 'falling' } : apple
})

As an aside: setState is asynchronous, so when you make multiple calls to setState, it may have not committed the previous call and therefore cause inconsistencies.

Upvotes: 0

Related Questions