Existe el requisito de cancelar las llamadas de solicitud cuando se navega fuera de la página o cuando se realizan varias llamadas a la misma llamada API (manteniendo la última activa).
Así es como se extrae la API (solo un nivel alto)
AJAX.ts
export async function customAjax(options){ let options = {}; options.headers = { ...options.headers, ...obj.headers }; const response = await fetch(url, options); await response.json() } Las llamadas GET y POST se extraen como
API.ts
const get = (url, extra = {}) => request({ url, type: "GET", ...extra }); const post = (url, payload, extra = {}) => request({ url, data: payload ,type: "POST", }, ...extra });En el componente de reacción llamo a estas utilidades de la siguiente manera:
function MyComponent(){ useEffect(() => { makeCall(); }, []); async function makeCall(){ const { response, error } = await API.post(URL, payload); // Handling code is not added here // In the similar fashion GET calls are also made } } Me encontré con Abortcontroller para abort la solicitud en la que podríamos usar el método de cancelación durante el desmontaje del componente.
¿Hay alguna manera de hacer esto a nivel de utilidad, puede estar dentro customAjax para evitar escribir el código del controlador de cancelación en todas partes?
Según tengo entendido... Lo que describe no es diferente a un problema de fuga de memoria. Y el método actual para evitar pérdidas de memoria es con AbortController() .
En cuanto a manejar esto en el "nivel de utilidad", no creo que esto sea factible y, de hecho, iría en contra de la noción preferida de que una API desconoce lo que sucede en el nivel del componente React; es decir separación de preocupaciones..
Entonces, para cumplir con su requisito, deberá usar AbortController() , o una implementación personalizada que use un indicador booleano que refleje si el componente está montado, por componente.
Usando el indicador booleano, puede aceptar un argumento en su API, pasando el indicador como parámetro; pero, de nuevo, creo que esto se consideraría un antipatrón.
Entiendo que está buscando una implementación mínima; pero la práctica estándar es bastante mínima:
useEffect(() => { let abortController = new AbortController(); // Async code return () => { abortController.abort(); } }, []);Usar una bandera booleana sería más detallado e implicaría algo como esto en su caso:
useEffect(() => { let isMounted = true; customAjax(isMounted); return () => { isMounted = false; } }, []);Para manejar respuestas ajax desordenadas, puede usar una variable local dentro del efecto. Por ejemplo,
useEffect(() => { let ignore = false; async function fetchProduct() { const response = await fetch('http://myapi/product/' + productId); const json = await response.json(); if (!ignore) setProduct(json); } fetchProduct(); return () => { ignore = true }; }, [productId]); La variable ignore se asegurará de que solo la respuesta de la última solicitud se actualice al estado. Referencia: https://reactjs.org/docs/hooks-faq.html#performance-optimizations
Con respecto a las preocupaciones sobre fugas de memoria, consulte esta discusión: https://github.com/reactwg/react-18/discussions/82