Reputation: 5389
I'm new to ReactJS. I have the following code, in which I try to update UI by updating state
using an onClick
event handler. However, the onClick
is not firing and it's not even showing on the final HTML. I can see the button but the button is not bound to the event handler. My code is:
import React from 'react';
class App extends React.Component {
constructor() {
super();
this.state = {
data: []
}
this.setStateHandler = this.setStateHandler.bind(this);
}
setStateHandler() {
var item = "setState...";
var myArray = this.state.data;
myArray.push(item)
this.setState({data: myArray})
}
render() {
return (
<div>
<button onClick = {this.setStateHandler}>SET STATE</button>
<h4>State Array: {this.state.data}</h4>
</div>
);
}
}
export default App;
My final HTML rendered on the browser is:
<html lang="en"><head>
<meta charset="UTF-8">
<title>React App</title>
<style type="text/css"></style></head>
<body>
<div id="app">
<div>
<button>SET STATE</button><h4>State Array: </h4>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
What am I doing wrong?
EDIT:
When I change var myArray = this.state.data;
to var myArray = this.state.data.slice();
it works as intended.
Upvotes: 0
Views: 1098
Reputation: 41
Try using {String(this.state.data)}
or {this.state.data.toString()}
instead.
Upvotes: 0
Reputation: 36179
You shouldn't see onClick
handler in your HTML, that's how React works.
Working code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
this.setStateHandler = this.setStateHandler.bind(this);
}
setStateHandler() {
var item = "setState...";
this.setState(prevState => ({ data: [...prevState.data, item]}));
}
render() {
return (
<div>
<button onClick = {this.setStateHandler}>SET STATE</button>
<h4>State Array: {this.state.data}</h4>
</div>
);
}
}
export default App
The problem in your example is within setStateHandler
definition. You are modifying state directly which is not a correct way to update state.
setStateHandler() {
var item = "setState...";
this.setState(prevState => ({ data: [...prevState.data, item]}));
}
In my example I use function as an argument to setState
(read when to use function as argument) which will pass me a copy of component state. Then I use destructuring assignment (...prevState) to create new array with a item
element. At last I return object to be merged into state.
Note that I used destructuring assignment for convenience and brevity. You can accomplish the same by just cloning the array:
setStateHandler() {
var item = "setState...";
this.setState(prevState => {
const newArray = prevState.data.slice();
newArray.push(item);
return { data: newArray };
});
}
Beside that you should also pass props
to base constructor.
But that wasn't the issue in this case.
Upvotes: 1