DCR
DCR

Reputation: 15700

reactjs state not being updated

in my filter() callback newList contains the correct array but state is not being updated.

<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8" />
      <title>list</title>
      <script src="react/react.js"></script>
      <script src="react/react-dom.js"></script>
      <script src="https://unpkg.com/[email protected]/babel.min.js"></script>
   </head>
   <body>
      <div id='container'>
      </div>
   </body>
</html>


<script type = 'text/jsx'>

class FilteredList extends React.Component{
   constructor(props){
      super(props);
      this.state={list:this.props.list};
   }

   filter(input){
      var newList = this.state.list.filter(function(item){
         return (item.search(input.target.value)!=-1);
      });
      console.log(newList);
      this.setState({list:newList});
      console.log(this.state.list);
   }

   render(){
      return(
         <div>
            <input type='text' placeholder='Filter' onChange={this.filter.bind(this)} />
            <List items={this.state.list} />
         </div>
      );
   }
}

class List extends React.Component{
   constructor(props){
      super(props);
      this.state={items:this.props.items};
   }

   render(){
      return(
         <ul>
            {this.state.items.map(function(item){
               return(<li key={item}>{item}</li>);
            })}
         </ul>

      );
   }
}

   ReactDOM.render(
      <div><FilteredList list={['anteater','bear','cat','dog','elephant','fox']} /></div>,
      document.getElementById('container')
);
</script>

Upvotes: 0

Views: 126

Answers (2)

Asif Amin
Asif Amin

Reputation: 16

For the state to be updated and the filtered result to display you need to re-render the child components on parent state change.

https://codepen.io/asifamingov/pen/QWwNOgQ

class List extends React.Component{
  constructor(props){
    super(props);
    this.state={items:this.props.items};
   }
   componentWillReceiveProps({items}) {
    this.setState({items:items});
   }
   render(){
     return(
        <ul>
            {this.state.items.map(function(item){
                return(<li key={item}>{item}</li>);
            })}
        </ul>

    );
   }
  }

And one more issue I found is that you are mutating your original state

class FilteredList extends React.Component{
  constructor(props){
    super(props);
    this.state={list:this.props.list, updatedList: this.props.list};
   }
  filter(input){
    var updatedList = [...this.state.list];
    var newList = updatedList.filter(function(item){
        return item.toLowerCase().search(
            input.target.value.toLowerCase()) !== -1;
    });
    this.setState({updatedList:newList});
  }
  render(){
    return(
        <div>
            <input type='text' placeholder='Filter' onChange={this.filter.bind(this)} />
            <List items={this.state.updatedList} />
        </div>
    );
   }
 }

Upvotes: 0

Exifers
Exifers

Reputation: 2852

This is because setState is asynchronous. This means that the state is not immediately updated when the line is executed, but some moment later.

To execute code once the state has been updated, setState takes a callback as second argument :

this.setState({list:newList}, () => console.log(this.state.list))

Upvotes: 3

Related Questions