There is an input element in my code:
<input id="input" className="ml-2" type="number" name="Qty" min="1" max="999" value={qty} onChange={(e) => {changeQty(e)}}/>
And the onChange handler is:
const changeQty = (e) => {
setQty(e.target.value);
console.log(qty);
}
So I suppose that whatever I enter in the input field will be printed out in the console, but the fact is there is delay.
For example, the default value is 1, then I type 2, then 1 will be printed out. Then I type 3, then 2 will be printed out. The number printed out is the previous one I entered instead of the current one, as shown below:
Could anyone tell me how to remove the delay?
I read useState set method not reflecting change immediately, but still cannot solve it.
I tried the code below as the answer indicates,
useEffect(() => {
setQty(document.getElementById("input").value)
}, [qty]);
but an error ReferenceError: Cannot access 'qty' before initialization
occurred.
Thanks!
There is an input element in my code:
<input id="input" className="ml-2" type="number" name="Qty" min="1" max="999" value={qty} onChange={(e) => {changeQty(e)}}/>
And the onChange handler is:
const changeQty = (e) => {
setQty(e.target.value);
console.log(qty);
}
So I suppose that whatever I enter in the input field will be printed out in the console, but the fact is there is delay.
For example, the default value is 1, then I type 2, then 1 will be printed out. Then I type 3, then 2 will be printed out. The number printed out is the previous one I entered instead of the current one, as shown below:
Could anyone tell me how to remove the delay?
I read useState set method not reflecting change immediately, but still cannot solve it.
I tried the code below as the answer indicates,
useEffect(() => {
setQty(document.getElementById("input").value)
}, [qty]);
but an error ReferenceError: Cannot access 'qty' before initialization
occurred.
Thanks!
Share Improve this question edited May 29, 2020 at 16:17 Snookums asked May 29, 2020 at 16:12 SnookumsSnookums 1,3605 gold badges25 silver badges54 bronze badges 3- Without the whole code it's impossible to answer this question. – Fez Vrasta Commented May 29, 2020 at 16:13
- Where are you calling setState? A console.log outside the setState context will print the old value. – aksappy Commented May 29, 2020 at 16:17
- 1 This boils down to the classic: "React setState is async" you have to use a callback or an effect to wait until the new state is set before using it. – DBS Commented May 29, 2020 at 16:23
4 Answers
Reset to default 6It's hard to say from the current question, but I'm going to assume that you're writing a function ponent and are using a useState
hook. That is, somewhere above the changeQty
you have something like:
const [qty, setQty] = useState(0);
If that's the case, then the answer is directly in the assignment of qty above. qty
is set when you call the useState
hook and will not change for the duration of the execution.
setQty
does not update the value of qty. It updates the internal state, which will trigger a re-render. That means the next time your render function is invoked, qty
will have the value you used.
But for the rest of the execution of the function, qty
will remain whatever value it was when useState
was called.
If you need the new value of qty
in the same iteration of your function, you can capture that as a new variable.
const [qty, setQty] = useState(0);
let updatedQty = qty;
const changeQty = (e) => {
updatedQty = e.target.value;
setQty(updatedQty);
console.log(updatedQty);
}
this.setState()
has two forms that could help you here:
Functional Form
this.setState((prevState, props) => ({}))
Callback Form
this.setState(nextState, () => {
// instructions for immediately-after the state update
})
It sounds like you could use the callback form here to defer some calculations into the callback.
Also, you can chain those if it's a warzone out there:
this.setState(nextState, () => {
this.setState(nextState, () => {
this.setState(nextState, () => {
// you can do this, but probably don't
})
})
})
But, notice the extreme indenting that is occurring; it's reminiscent of callback hell and Promise christmas-tree hell.
The problem is that setQty is asynchronous. Try this:
useEffect(() => {
console.log(qty);
}, [qty]);
You will normally get current value in this console.log.
In your code, your console.log may execute before the state is updated because setQty
not synchronous as you may think
Since you didn't share all of your code, it's difficult to answer your question exactly, but it looks like you're using React's hooks, so I've created an example that uses hooks correctly to set the qty
state and log the current qty
value.
const Quantity = function() {
const [qty, setQty] = React.useState(0);
const changeQty = (e) => {
setQty(e.target.value);
};
React.useEffect(() => {
console.log(qty);
}, [qty]);
return (
<input id="input" className="ml-2" type="number" name="Qty" min="1" max="999" value={qty} onChange={(e) => {changeQty(e)}}/>
);
};
ReactDOM.render(<Quantity />, document.getElementById("app_root"));
<head>
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/babel-core/5.8.25/browser-polyfill.min.js"></script>
</head>
<body>
<div id="app_root"></div>
</body>