Cuando trabajas con React, tarde o temprano te vas a topar con situaciones donde necesitas ejecutar tareas que toman tiempo, como consultar una API cada cierto tiempo para ver si un proceso terminó. Si no lo manejas bien, puedes trabar la app o saturar el navegador. Para evitar eso, podemos usar Web Workers.
Voy a explicarte un ejemplo que hice para monitorear el estado de un reporte que se genera en el backend.
¿Qué Necesitamos Hacer?
Llamar a la API para iniciar el proceso de generación del reporte.
Obtener un task_id que identifica esa tarea.
Consultar cada 30 segundos si la tarea ya terminó.
Manejar todo esto sin afectar la interfaz del usuario.
El truco aquí está en usar un Web Worker, que es como un ayudante en segundo plano que se encarga de hacer todo el trabajo pesado sin bloquear la app.
El Código
Paso 1: Configura Axios para la API
Lo primero es preparar Axios para que pueda conectarse a la API. Aquí configuro un cliente que tiene la URL base y los headers que necesito:
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",
},
});
Paso 2: Crea el Web Worker
El Web Worker es donde pasa la magia. Básicamente, este chico está revisando la API cada 30 segundos para ver si la tarea ya terminó:
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();
};
Paso 3: Maneja el Worker en React
En tu app React, necesitas controlar este Web Worker: iniciarlo, pasarle datos, y manejar las respuestas que te manda.
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;
}
}
}
Paso 4: Uso en el componente
Ahora, en el componente de React, utilizamos el AsyncTaskManager para gestionar la tarea. El proceso incluye iniciar la tarea, mostrar un cargando, y actualizar el estado cuando se recibe el resultado de la tarea:
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>
);
};
Explicación del Flujo
Generar el Reporte: Al hacer clic en "Iniciar Tarea", se llama a una API que inicia el proceso de generación del reporte y devuelve un task_id
.
Monitoreo en Segundo Plano: Usamos un Web Worker que recibe este task_id
y consulta la API de estado cada 30 segundos, enviando el estado de la tarea de vuelta a React.
Actualizar UI: Mientras la tarea se ejecuta, la UI permanece fluida, con un botón que muestra "Procesando..." y, una vez completada la tarea, muestra el resultado.
Liberar Recursos: Cuando la tarea termina (ya sea con éxito o fracaso), el Worker se detiene para liberar recursos y evitar procesos innecesarios en segundo plano.
¿Por Qué Hacerlo Así?
Este enfoque es súper útil porque:
No bloqueas la interfaz del usuario mientras consultas la API.
Puedes manejar procesos largos sin que la app se congele.
El usuario siempre sabe qué está pasando gracias a los loaders y notificaciones.
Top comments (0)