ecosystem-wikicómo extender los templates sin romper sus convenciones
‹ todas las recipes

¿useFetch o usePaginatedFetch?

template-expo
último cambio 2026-09-25

Cargar datos de la api tiene exactamente dos formas, y ninguna pantalla debería escribir la tercera.

Hook Para Devuelve
useFetch Un recurso suelto: el perfil, los ajustes, una mascota { data, loading, error, setData, reload }
usePaginatedFetch Listas que crecen con scroll { items, total, loading, loadingMore, error, hasMore, loadMore }

Si el endpoint devuelve una lista paginada, usePaginatedFetch. Para todo lo demás, useFetch.

Encima de ellos, un hook por recurso que solo aporta la llamada y el mensaje de error. Así se leen en una pantalla:

const { data: profile, loading, setData } = useProfile();

Y así se escribe uno nuevo — suelen ser tres líneas:

export function usePetReports(petId: string) {
  return usePaginatedFetch((page, limit) => listReports(petId, page, limit), petId, 10);
}

El parámetro key

Es lo que hace que el hook se recargue cuando cambia el recurso, no cuando cambia cualquier cosa:

setData es para actualizaciones optimistas

useFetch expone el setData a propósito: escribe el valor nuevo al momento y revierte si la llamada falla. Es lo que hace que un interruptor de ajustes se sienta instantáneo.

Por qué el estado no se toca dentro del efecto

Es la parte del código con más razonamiento detrás, y la que alguien intentará “arreglar”:

const [loading, setLoading] = useState(true);      // ya arranca cargando
// ...
const [lastKey, setLastKey] = useState(key);
if (key !== lastKey) {                             // durante el render, no en un efecto
  setLastKey(key);
  setData(null);
  setLoading(true);
}

Dos decisiones ahí:

  1. loading empieza en true y solo se reinicia desde reload(). No hace falta ponerlo dentro del efecto porque el estado inicial ya es el estado de carga.
  2. El reinicio al cambiar key se hace durante el render, que es la recomendación de React para “ajustar estado cuando cambia una prop”.

El motivo de fondo: escribir estado en el cuerpo de un efecto provoca un render en cascada, y la regla react-hooks/set-state-in-effect lo marca. Hacerlo así mantiene el hook limpio y el lint en verde.

El guard del token

Los dos hooks empiezan igual:

if (!accessToken) return;

No es defensivo por si acaso: apiFetch lee el token de una variable de módulo que se rellena como efecto secundario del login, así que un hook no puede fiarse del orden de montaje. Sin este guard, una pantalla que monta antes de que la sesión se restaure lanzaría la petición sin Authorization. Ver hablar con la api.

La dependencia que se excluye a propósito

Los dos hooks llevan un eslint-disable sobre exhaustive-deps para omitir la función de carga. Está justificado y comentado: esa función se recrea en cada render pero siempre encierra key, que es la dependencia real. Incluirla provocaría una petición por render.

Es la única excepción aceptada a exhaustive-deps en el repo. Si te hace falta otra, casi siempre significa que la función debería estar envuelta en useCallback en su origen.