I have a React component with a state variable jobs
. When the state variable ready
is true, it should start executing jobs by a Web Worker (one at a time).
import React, { useEffect, useRef } from 'react'
// create webworker
const job_worker = new Worker("worker.bundle.js", { type: "module" });
function App() {
const [jobs, set_jobs] = React.useState([
{ ... },
{ ... },
])
const [ready, set_ready] = React.useState(false)
// start worker loop
useEffect(() => {
const worker_loop = async () => {
setTimeout(async () => {
// check if ready to execute a job
if (ready) { // <== suffers from 'stale closure'
// grab a job
const job = jobsRef.current.find(j => !j.done)
// listen for webworker results
job_worker.onmessage = (e) => {
console.log("received response from webworker: '", e.data, "'")
// SET RESULT IN JOB
// job is handled by worker; now start the worker_loop again
return worker_loop()
}
// post job to worker
job_worker.postMessage({job: job})
return // do not continue; 'onmessage' will continue the loop
}
return worker_loop()
}, 1000)
}
// start worker_loop
worker_loop()
}, [])
return (
<div>
{/* code to add jobs and set ready state */}
</div>
);
}
I tried to do this by using an (infinite) worker_loop
, which is started when the React component mounts (using useEffect). The loop kinda works, but the ready
variable inside the worker_loop
stays at the initial state value (known as the 'stale closure' problem). Probably the same for the jobs
state variable.
I've already tried to use 'createRef' as suggested here. But the problem persists. Also I feel like there is a much simpler solution.
Is there a better way to handle 'jobs' in a React-state variable? Some sort of 'job-runner process/function' with access to the React component. By the way, I am not obliged to use WebWorker.