How to Use Web Workers in React for Background Tasks
In React, you can use
Web Workers to run heavy tasks in the background by creating a worker script and communicating with it via postMessage and onmessage. Use the useEffect hook to start and clean up the worker, ensuring your UI stays responsive.Syntax
To use a web worker in React, you create a new Worker instance with the path to your worker script. Then, you send messages to the worker using postMessage and listen for responses with onmessage. Clean up the worker when the component unmounts.
new Worker('worker.js'): creates the workerworker.postMessage(data): sends data to the workerworker.onmessage = (event) => {}: receives data from the workerworker.terminate(): stops the worker
javascript
const worker = new Worker('worker.js'); worker.postMessage('start'); worker.onmessage = (event) => { console.log('Message from worker:', event.data); }; // When done worker.terminate();
Example
This example shows a React component that uses a web worker to calculate Fibonacci numbers without freezing the UI. The worker runs the calculation and sends the result back.
javascript
import React, { useState, useEffect, useRef } from 'react'; // worker.js content as a Blob const workerCode = () => { self.onmessage = (e) => { const fib = (n) => { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); }; const result = fib(e.data); self.postMessage(result); }; }; const codeAsString = workerCode.toString(); const blob = new Blob(['(' + codeAsString + ')()'], { type: 'application/javascript' }); const workerUrl = URL.createObjectURL(blob); export default function FibonacciWorker() { const [input, setInput] = useState(10); const [result, setResult] = useState(null); const workerRef = useRef(null); useEffect(() => { workerRef.current = new Worker(workerUrl); workerRef.current.onmessage = (e) => { setResult(e.data); }; return () => { workerRef.current.terminate(); URL.revokeObjectURL(workerUrl); }; }, []); useEffect(() => { if (workerRef.current) { setResult('Calculating...'); workerRef.current.postMessage(input); } }, [input]); return ( <main> <label htmlFor="fibInput">Enter a number:</label> <input id="fibInput" type="number" min="0" max="40" value={input} onChange={(e) => setInput(Number(e.target.value))} aria-label="Fibonacci input number" /> <p>Fibonacci result: <strong>{result}</strong></p> </main> ); }
Output
User enters a number, e.g., 10, and the page shows: Fibonacci result: 55
Common Pitfalls
Common mistakes when using web workers in React include:
- Not terminating the worker on component unmount, causing memory leaks.
- Trying to import React or DOM APIs inside the worker script (workers run in a separate thread without access to DOM).
- Passing complex objects that are not serializable via
postMessage. - Not handling worker errors or messages properly.
Always clean up workers and keep worker code simple and self-contained.
javascript
/* Wrong: Not terminating worker */ useEffect(() => { const worker = new Worker('worker.js'); worker.postMessage('start'); worker.onmessage = (e) => console.log(e.data); // Missing worker.terminate() on cleanup }, []); /* Right: Terminate worker on cleanup */ useEffect(() => { const worker = new Worker('worker.js'); worker.postMessage('start'); worker.onmessage = (e) => console.log(e.data); return () => { worker.terminate(); }; }, []);
Quick Reference
Tips for using web workers in React:
- Use
useEffectto create and clean up workers. - Communicate with workers using
postMessageandonmessage. - Keep worker code free of React or DOM dependencies.
- Use Blob URLs for inline workers or separate files for bigger projects.
- Terminate workers to avoid memory leaks.
Key Takeaways
Create and terminate web workers inside React's useEffect to manage lifecycle.
Use postMessage and onmessage to send and receive data between React and the worker.
Keep worker scripts simple and free from React or DOM code.
Use Blob URLs for inline workers to avoid extra files.
Always terminate workers to prevent memory leaks.