I have created some state at the top level component (App), however it seems that when this state is updated, the updated state is not read by the asynchronous function defined in useEffect()
(it still uses the previous value), more detail below:
I am attempting to retrieve the state of the const processing
in the async function toggleProcessing
defined in useEffect()
, so that when processing
becomes false, the async function exits from the while loop. However, it seems that when the processing
updates to false, the while loop still keeps executing.
The behaviour should be as follows: Pressing the 'Begin Processing' button should console log "Processing..." every two seconds, and when that same button is pressed again (now labeled 'Stop Processing'), then "Stopping Processing" should be console logged. However, in practice, "Stopping Processing" is never console logged, and "Processing" is continuously logged forever.
Below is the code:
import React, { useState, useEffect} from 'react'
const App = () => {
const [processing, setProcessing] = useState(false)
const sleep = (ms) => {
return new Promise(resolve => setTimeout(resolve, ms))
}
useEffect(() => {
const toggleProcessing = async () => {
while (processing) {
console.log('Processing...')
await sleep(2000);
}
console.log('Stopping Processing')
}
if (processing) {
toggleProcessing() // async function
}
}, [processing])
return (
<>
<button onClick={() => setProcessing(current => !current)}>{processing ? 'Stop Processing' : 'Begin Processing'}</button>
</>
)
}
export default App;
It really just comes down to being able to read the updated state of processing
in the async function, but I have not figure out a way to do this, despite reading similar posts.
Thank you in advance!
CodePudding user response:
If you wish to access a state when using timeouts, it's best to keep a reference to that variable. You can achieve this using the useRef
hook. Simply add a ref with the processing value and remember to update it.
const [processing, setProcessing] = useState<boolean>(false);
const processingRef = useRef(null);
useEffect(() => {
processingRef.current = processing;
}, [processing]);