SetState does not update state: ReactJS
I feel like I've tried everything under the sun here, but must be missing something very obvious. In addItem() function
below, I'm trying to insert a new item into the state of the array and updates, but no matter what I do, it just won't change from the original array.
When I console.log newListItems a new item is added, so everything up to this point works, this is the actual state that will not be updated. 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 an error in the console.
Complete 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;
source to share
The problem is you are updating state
incorrectly, use this:
this.setState({
listItems : newListItems
});
Instead of this:
this.setState = ({
listItems : newListItems
});
Cause:
Because setState is not a variable, we need to call this to update the state of the value.
Check this answer for more information on setState .
Other suggestions :
When you assign any array
to any variable, the variable only gets a reference array
, meaning that any changes you make will be directly applied to the original array
. And it's not recommended to mutate the variable right away state
, so first create a copy array
with slice
, then use push
to add an item to that. Like this:
var newListItems = this.state.listItems.slice();
newListItems.push(text);
this.setState({
listItems : newListItems
});
By DOC :
Never mutate this.state directly, as calling setState () may subsequently replace the mutation you made. Treat this. As if it is unchanging.
Check out a 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' />
source to share