Reputation: 315
I have an app which calls two functions; MyCart and MyItems. I am trying to make it so when the button rendered in MyItems is called it calls a method inside the main app component (the parent) and changes the state but for some reason, it doesn't change the value in the MyCart span.
My code below is what I am trying to do but it's not working and I can't figure out why.
class ShopRemake extends React.Component {
constructor() {
super();
this.state = {
total: 0
}
this.changeTotal = this.changeTotal.bind(this);
}
changeTotal() {
this.setState(prevState => {total: ++prevState.total});
console.log(this.state);
}
render() {
return (
<React.Fragment>
<MyItem changeTotal={this.changeTotal}/>
<MyCart total={this.state.total}/>
</React.Fragment>
);
}
}
function MyItem(props) {
return (
<button onClick={props.changeTotal}> Click Me </button>
);
}
function MyCart(props) {
return (
<span> Total Items: {props.total} </span>
);
}
I want it so that after I click the button the span inside the MyCart to update accordingly.
Upvotes: 1
Views: 77
Reputation: 7492
You must wrap the returning object literal into parentheses in your arrow functions. Otherwise curly braces will be considered to denote the function’s body. The following works:
p => ({ foo: 'bar' })
So the call to setState
in changeTotal
:
changeTotal() {
this.setState(prevState => {total: ++prevState.total});
console.log(this.state);
}
Should be replaced by the following :
changeTotal() {
this.setState(prevState => ({total: ++prevState.total}));
console.log(this.state);
}
Also, setState
is asynchronous, you will need to either await it(not recommended) or use the callback as the second parameter to see the resulting state :
changeTotal() {
this.setState(
prevState => ({total: ++prevState.total}),
() => { console.log(this.state) }
);
}
EDIT :
Sidenote, the 2 components below in your code can be reduced into arrow functions for the exact same result, while making them easier to read :
const MyItem = ({ changeTotal }) => <button onClick={changeTotal}> Click Me </button>
const MyCart = ({ total }) => <span> Total Items: {total} </span>
And you can also convert changeTotal
to an arrow function to avoid having to bind it in your constructor
Upvotes: 2
Reputation: 3270
Your setState is not returning an object here. Try to change your method changeTotal to this
changeTotal() {
this.setState(prevState => ({ total: prevState.total + 1 }), () =>
console.log(this.state));
}
The setState methods is asynchronous, if you want to log it's value, do this with a callback.
Upvotes: 2