Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setState is not updating state: ReactJS

Tags:

reactjs

I feel like I've tried everything under the sun here but must be missing something very obvious. In the addItem() function below, I am trying to push a new item into an array and update state, but no matter what I do state just won't change from the initial array.

When I console.log newListItems the new item is included, so everything up to that point is working, it's the actual state that won't update. What am I missing?

addItem Method:

addItem(text){
    var newListItems = this.state.listItems;
    newListItems.push(text);
    console.log(newListItems);

    this.setState = ({
        listItems : newListItems
    });

}

Also i am not getting any error message in console.

Full Code:

import React, { Component } from 'react';
import './App.css';
      
class ListItem extends Component{
  render(){
    return (<li>{this.props.title}</li>);
  }
}
     
class AddItem extends Component{

  handleClick(){
    this.props.addItem('blah');
  }

  render(){
    return (
      <div className="additem">
        <input type="text" className="newitemname"/>
        <span className="btn" onClick={this.handleClick.bind(this)}>Add item</span>
      </div>
    );
  }
}
    
    
class App extends Component {

  constructor(props){
    super(props);
    this.state = {
      listItems : ['Wash the dishes','Do the laundry','Something else']
    };
  }

  addItem(text){
    var newListItems = this.state.listItems;
    newListItems.push(text);
    console.log(newListItems);
    this.setState = ({
      listItems : newListItems
    });
  }

  render() {
    return (
      <div className="App">
        <ul>
          {this.state.listItems.map(function(item,index){
              return (
                  <ListItem key={index} title={item} />
              );
          })}
        </ul>
        <AddItem addItem={this.addItem.bind(this)} />
      </div>
    );
  }

}
    
    
export default App;
like image 220
MyNotes Avatar asked Apr 10 '17 13:04

MyNotes


1 Answers

Issue is, you are updating the state in a wrong way, Use this:

this.setState({
    listItems : newListItems
});

Instead of this:

this.setState = ({
    listItems : newListItems
});

Reason:

Because setState is a function not a variable, we need to call that to update the state values.

Check this answer for more details about setState behaviour.

Other Suggestions:

When you assign any array to any variable, variable will only get the reference of array, means all the changes that you will perform, will directly applied on the original array. And its not a good idea to mutate the state variable directly, so first create the copy of the array by using slice, then use push to add the item in that. Like this:

var newListItems = this.state.listItems.slice();
newListItems.push(text);
this.setState({
     listItems : newListItems
});

As per DOC:

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

Check the working example:

class ListItem extends React.Component{

  render(){
    return (<li>{this.props.title}</li>);
  }

}


class AddItem extends React.Component{

  handleClick(){
    this.props.addItem(this.item.value);
  }

  render(){
    return (
      <div className="additem">
        <input type="text" ref={item => this.item=item} className="newitemname"/>
        <span className="btn" onClick={this.handleClick.bind(this)}>Add item</span>
      </div>
    );
  }

}


class App extends React.Component {

  constructor(props){
    super(props);
    this.state = {
      listItems : ['Wash the dishes','Do the laundry','Something else']
    };
  }

  addItem(text){
    var newListItems = this.state.listItems.slice();
    newListItems.push(text);
    this.setState({
      listItems : newListItems
    });
  }

  render() {
    return (
      <div className="App">
        <ul>
          {this.state.listItems.map(function(item,index){
              return (
                  <ListItem key={index} title={item} />
              );
          })}
        </ul>
        <AddItem addItem={this.addItem.bind(this)} />
      </div>
    );
  }

}

ReactDOM.render(<App/>, document.getElementById('app'))
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app' />
like image 166
Mayank Shukla Avatar answered Sep 23 '22 12:09

Mayank Shukla