I have a button with which I start a test function:
<button type="button" onClick={startTestFrequencyList}>{
frequenciesTestRunning ? 'Stop Test Frequency' : 'Start Test Frequency'
}</button>
The startTestFrequencyList
either starts the testFrequencyList
or stops it.
const [stopTest, setStopTest] = useState(false);
const [frequenciesTestRunning, setFrequenciesTestRunning] = useState(false);
const startTestFrequencyList = () => {
if (frequenciesTestRunning) {
window.alert("Already testing")
setStopTest(true);
} else {
setFrequenciesTestRunning(true);
testFrequencyList();
}
}
Inside the startTestFrequencyList
function, I execute a lot of fetch calls in a loop which I want to stop if the user clicks the button again.
const testFrequencyList = async () => {
for (const item of frequencyList) {
try {
// Stop the fetching
if (stopTest) {
// STOP TEST
stopTest(false);
setFrequenciesTestRunning(false);
return;
}
const response = await fetch('http://127.0.0.1:8000/frequency/testWithRe/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item),
});
const testResult = await response.json();
// do something
} catch (error) {
console.error('Error:', error);
}
}
}
The problem is, whenever stopTest
is set to true, nothing happens. It seems like the function does not get the newest state of stopTest
.
You can use useRef
const refStop = React.useRef(false)
const startTest = React.useCallback(async () => {
const arr = new Array(10000).fill(0).map((_,i) => i)
for await (const i of arr ){
await new Promise((resolve) => setTimeout(resolve, 1000));
if (refStop.current) {
refStop.current = (false)
return console.log("stopped")
}
console.log("i", i)
}
},[refStop.current])
return (
<div className="App">
<button onClick={startTest}>start</button>
<button onClick={() => refStop.current = (true)}>stop</button>
</div>
);
But this will not abort the on-going promise. If you want to abort on going promises, you may want to use abort controllers
But what is
stopTest
? It’d help to show the entire component (in minimal reproducible example form of course) so that it’s clear which each variable and function is.Sorry. Added the
stopTest
state. The entire component is quite huge. I will try to reproduce an exampleYou’re creating a closure over
stopTest
. You could make it an object and mutate it? or use an abortController? see: Proper way to Abort (stop) running async/await function?The value of a state variable wont change until the component re-renders. Not sure if that’s the problem here.