When working with React, sooner or later you are going to run into situations where you need to execute tasks that take time, like checking an API every so often to see if a process has finished. If you don't handle it well, you can crash the app or saturate the browser. To avoid that, we can use Web Workers.
I'm going to explain to you an example I made to monitor the status of a report that is generated in the backend.
Call the API to start the report generation process.
Get a task_id that identifies that task.
Check every 30 seconds if the task is finished.
Handle all this without affecting the user interface.
The trick here is to use a Web Worker, which is like a background helper that does all the heavy lifting without blocking the app.
The first thing is to prepare Axios so that it can connect to the API. Here I configure a client that has the base URL and the headers I need:
import axios from "axios"; export const apiClient = axios.create({ baseURL: "https://example.com/api", // Cambia esta URL por la base de tu API headers: { "Content-Type": "application/json", Accept: "application/json", }, });
The Web Worker is where the magic happens. Basically this guy is checking the API every 30 seconds to see if the task is already finished:
self.onmessage = async (event) => { const { task_id, apiEndpoint } = event.data; const checkTaskStatus = async () => { try { const response = await fetch(`${apiEndpoint}/${task_id}`); const task = await response.json(); self.postMessage(task); if (task.status !== "SUCCESS" && task.status !== "FAILURE") { setTimeout(checkTaskStatus, 30000); } } catch (error) { console.error("Error en el Worker:", error); } }; checkTaskStatus(); };
In your React app, you need to control this Web Worker: start it, pass data to it, and manage the responses it sends you.
export class AsyncTaskManager { private worker: Worker | null = null; public async startTask(taskId: string, apiEndpoint: string, onResult: (data: any) => void) { if (this.worker) { this.worker.terminate(); } this.worker = new Worker(new URL("./GenericWorker.js", import.meta.url), { type: "module" }); this.worker.postMessage({ task_id: taskId, apiEndpoint }); this.worker.onmessage = (event) => { const data = event.data; onResult(data); if (data.status === "SUCCESS" || data.status === "FAILURE") { this.stopWorker(); } }; } public stopWorker() { if (this.worker) { this.worker.terminate(); this.worker = null; } } }
Now, in the React component, we use the AsyncTaskManager to manage the task. The process includes starting the task, displaying a loading, and updating the status when the result of the task is received:
import React, { useState } from "react"; import { AsyncTaskManager } from "./AsyncTaskManager"; const taskManager = new AsyncTaskManager(); export const ExampleComponent = () => { const [isLoading, setIsLoading] = useState(false); const [result, setResult] = useState(null); const handleStartTask = async () => { setIsLoading(true); // Simula el inicio de una tarea en el backend const response = await fetch("https://example.com/api/start-task", { method: "POST", headers: { "Content-Type": "application/json", }, }); const { task_id } = await response.json(); taskManager.startTask(task_id, "https://example.com/api/task-status", (data) => { if (data.status === "SUCCESS" || data.status === "FAILURE") { setIsLoading(false); setResult(data.result); // Maneja el resultado de la tarea } }); }; return ( <div> <button onClick={handleStartTask} disabled={isLoading}> {isLoading ? "Procesando..." : "Iniciar Tarea"} </button> {result && <div>Resultado: {JSON.stringify(result)}</div>} </div> ); };
Generate the Report: Clicking "Start Task" calls an API that starts the report generation process and returns a task_id.
Background Monitoring: We use a Web Worker that receives this task_id and queries the status API every 30 seconds, sending the task status back to React.
Refresh UI: While the task is running, the UI remains fluid, with a button showing "Processing..." and once the task is completed, showing the result.
Release Resources: When the task finishes (either success or failure), the Worker stops to free resources and avoid unnecessary background processes.
This approach is super useful because:
You don't block the user interface while querying the API.
You can handle long processes without the app freezing.
The user always knows what is happening thanks to loaders and notifications.
The above is the detailed content of How to Run Asynchronous Tasks in React Using Web Workers. For more information, please follow other related articles on the PHP Chinese website!