This question already has an answer here:
Why doesn't my arrow function return a value?
(1 answer)
Closed 3 years ago.
Following is my code in which I am trying to increment the count using click button but it's not updating the value. Though I am not getting any error in console as well. Let me know what I am doing wrong here.
JS Code -
class App1 extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
this.setCount = this.setCount.bind(this)
}
setCount() {
this.setState((state) => {
count: state.count + 1
})
}
render() {
return (
<>
<hr />
<h3>test increment</h3>
<button onClick={this.setCount}>Click</button>
<p>{this.state.count}</p>
</>
)
}
}
ReactDOM.render(<App1 />, document.getElementById('root'))
Codepen - https://codepen.io/anon/pen/LaMOEp
You are not returning anything. You could use return in side callback.
setCount() {
this.setState((state) => {
return {count: state.count + 1}
}))
}
Or you can use avoid using of return wrapping you return value in () after =>
setCount() {
this.setState((state) => ({
count: state.count + 1
}))
}
this.setState((state) => {
count: state.count + 1
})
In the above code, the curly brackets are the body of the function, count: is a line label, and state.count + 1 is an expression that never gets used. If you want to use the concise arrow function syntax to return an object literal, then you need to wrap the object in parentheses:
this.setState((state) => ({
count: state.count + 1
}))
The problem is in setCount(), where you miss a pair of parenthesis! Here's the correct version:
setCount() {
this.setState((state) => ({
count: state.count + 1
}));
}
There are two parenthesis more! One right after the => and one at then of the this.setState() call.
Related
I learning design ui with react library. But I don't know what happended in my code.
handleIncrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity + 1
});
console.log(this.state);
document.getElementsByClassName("Counter-Order")[0].innerHTML++;
};
handleDecrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity > 1 ? this.state.quantity - 1 : 1
});
if (this.state.quantity > 1) {
document.getElementsByClassName("Counter-Order")[0].innerHTML--;
}
};
Result image
Please have a look I hope it's helpful
Thanks
handleIncrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity + 1
},()=>{
console.log(this.state);
document.getElementsByClassName("Counter-Order")[0].innerHTML++;
});
};
handleDecrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity > 1 ? this.state.quantity - 1 : 1
},()=>{
if (this.state.quantity > 1) {
document.getElementsByClassName("Counter-Order")[0].innerHTML--;
}
});
};
This is the intended behaviour. The set state updates the state after the function has executed since it's an asynchronous function.
So actually what happens is.
The setState is called.
Console log happens.
State updates.
So to check the state after setState use the 2nd parameter (callback) in the set state.
this.setState(
{ ...this.state,
quantity: this.state.quantity + 1 },
() => console.log(this.state
);
You are violating the main idea of React by directly accessing DOM like document.getElementsByClassName("Counter-Order")[0].innerHTML++;
Ideally You should have something like this in your render function.
render() {
return <div className="Counter-Order">{this.state.quantity}</div>;
}
setState is an asynchronous function.
React internally waits for the best moment to change the state and re-render the component.
So the new state value isn't available immediatly after executing setState. That's why in your case your console.log still shows the previous state value.
Consider the following code :
import React, { Component } from 'react';
class Counter extends Component {
state = { value: 5 };
increment = () => {
this.setState(prevState => ({
value: prevState.value + 1
}));
};
decrement = () => {
this.setState(prevState => ({
value: prevState.value - 1
}));
};
render() {
return (
<div>
{this.state.value}
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
)
}
}
How can I make it so that whenever I click the Decrement button, the value will not be less than 0. The value's minimum will always be zero and not -1, -2 ,-3 ,-4 ...
Just set a minimum value in your decrementing code:
decrement = () => {
this.setState(prevState => ({
value: Math.max(prevState.value - 1, 0)
}));
};
That's how number input works. To simplify the code you could try to use validity state (if your target browsers support it)
onChange(e) {
if (!e.target.validity.badInput) {
this.setState(Number(e.target.value))
}
}
Example
you can test it
const onPressDecrement = () => setCount((prevCount) => (Math.max(prevCount - 1,1)));
On Way Use Conditional (ternary) operator in decrement Function
decrement = () => {
this.setState(prevState => ({
value: prevState.value ? prevState.value -1 : 0
}));
};
this.setState(prevState => ({
score: prevState.score + 10,
rightAnswers: prevState.rightAnswers + 1,
currentQuestion: setTimeout(() => {
prevState.currentQuestion + 1
}, 2000)
}))
}
On button click I change the state. My goal is to have a delay in currentQuestion state change, during which I want to show certain status messages, yet I want to update the score right away without delays.
What's the proper way to do that?
PS: This variant doesn't work, it's for the overall representation of what I want to do.
Thanks.
You can do this multiple ways:
1) Make two calls to setState. React will batch any concurrent calls to setState into one batch update, so something like this is perfectly fine:
this.setState( prevState => ({
score: prevState.score + 10,
rightAnswers: prevState.rightAnswers + 1
}));
setTimeout( () => {
this.setState( prevState => ({
currentQuestion: prevState.currentQuestion + 1
}));
}, 2000);
2) You can use the setState callback to update state after your first call is finished:
this.setState(prevState => ({
score: prevState.score + 10,
rightAnswers: prevState.rightAnswers + 1
}), () => {
setTimeout( () => {
this.setState( prevState => ({
currentQuestion: prevState.currentQuestion + 1
}));
}, 2000);
});
First use setState to change score and question with some value like null so that you know its updating and then also set timeout after that.
class Example extends React.Component {
constructor(props) {
super(props)
this.state = {
score: 1,
question: "A"
}
}
update() {
this.setState(prev => ({
score: prev.score + 1,
question: null
}));
this.change = setTimeout(() => {
this.setState({question: "B"})
}, 2000)
}
render() {
let {score, question} = this.state;
let style = {border: "1px solid black"}
return (
<div style={style} onClick={this.update.bind(this)}>
<div>{score}</div>
<div>{question ? question : "Loading..."}</div>
</div>
)
}
}
ReactDOM.render( < Example / > , document.querySelector("#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"></div>
I understand that react doesn't update state immediately then can someone tell me how i can log this state synchronously as my state is not a boolean and this answer didn't help me setState doesn't update the state immediately. Also i don't understand why after clicking on prev button it increments the value first and then it decrements
class A extends Component {
constructor(props) {
super(props);
this.state = {
value: 1
}
}
handleNext() {
this.setState(prevState => ({
value: prevState.value + 1
}));
console.log(this.state.value);
}
handlePrev() {
if(this.state.value > 1) {
this.setState(prevState => ({
value: prevState.value - 1
}));
}
console.log(this.state.value);
}
render() {
<Button bsStyle="primary" id="prev" onClick={() => this.handlePrev()}>Prev</Button>
<Button bsStyle="primary" id="next" onClick={() => this.handleNext()}>Next</Button>
}
The second argument to setState is a callback that executes after the state has updated.
handleNext() {
this.setState({ value: this.state.value + 1 }, () => ({
console.log(this.state.value);
});
}
From the setState docs:
The second parameter to setState() is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead.
setState takes a callback as its second argument.
handleNext() {
this.setState(prevState => ({
value: prevState.value + 1
}),() => console.log('updated', this.state.value));
}
You code is fine, try printing this.state.value in your render function.
Example:
class A extends Component {
constructor(props) {
super(props);
this.state = {
value: 1,
};
}
handleNext() {
this.setState(prevState => ({
value: prevState.value + 1,
}));
}
handlePrev() {
if (this.state.value > 1) {
this.setState(prevState => ({
value: prevState.value - 1,
}));
}
}
render() {
const { value } = this.state;
return (
<div>
<h2>{ value }</h2>
<button id="prev" onClick={() => this.handlePrev()}>Prev</button>
<button id="next" onClick={() => this.handleNext()}>Next</button>
</div>
);
}
}
It seems like your handlePrev is incrementing then decrementing because you're constantly printing the previous state. So when you decrement you are printing the result of the previous increment.
|---------------------|-------------------------|
| Current State | Your console.log |
|---------------------|-------------------------|
| 1 | | init
|---------------------|-------------------------|
| 2 | 1 | increment
|---------------------|-------------------------|
| 3 | 2 | increment
|---------------------|-------------------------|
| 2 | 3 | decrement
|---------------------|-------------------------|
In my increaseCount method I have 3 different ways of increasing the count. I thought the first method could be used twice but it doesn't work as it seems to merge the setState in the callback. What's the proper way to use a callback function and why does the arrow notation work? How is prevState.count being defined? It is never set to 0
import React from "react";
import { render } from "react-dom";
const styles = {
fontFamily: "sans-serif",
textAlign: "center"
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increaseCount() {
console.log(this);
this.setState({ count: this.state.count }, function() {
this.setState({ count: this.state.count + 1 });
});
this.setState({ count: this.state.count + 1 });
this.setState(prevState=>({ count: prevState.count + 1 }));
}
render() {
return (
<div style={styles}>
<div>
<button onClick={() => this.increaseCount()}>Increase</button>
</div>
<h2>{this.state.count}</h2>
</div>
);
}
}
render(<App />, document.getElementById("root"));
this.setState(prevState=>({count: prevState.count + 1}))
this.setState(function(prevState) {
return {count: prevState.count + 1};
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
this.setState(function (prevState) {
return {count: prevState.count + 1};
});
https://reactjs.org/docs/react-component.html#setstate
https://codepen.io/anon/pen/BrRzgB?editors=1011
Both prevState and props received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with prevState.
setState(updater[, callback])