Inicio / Artículos

Mantén las listas de React Query actualizadas con refetchOnMount después de la navegación

Aprenda por qué TanStack Query muestra filas obsoletas en la lista después de realizar ediciones, cuando invalidQueries no es suficiente, y cómo refetchOnMount vuelve a validarlas en cada nuevo montaje.

Editor: REACTAPP.TOP5 min de lectura1052 palabras

Fuentes: How `refetchOnMount` in React Query Solves Stale Data Problems Across Components

Mantener un caché de clientes actualizado en todas las rutas es más difícil que realizar la primera solicitud. Imagine una consola de administración con una tabla de usuarios en una pantalla y un formulario de edición en otra. Al guardar un nombre, la navegación vuelve a la lista, pero el nombre antiguo sigue apareciendo en pantalla.

Ese patrón se produce cada vez que TanStack Query (React Query) utiliza un caché ya cargado en lugar de volver a conectarse a la red. La opción refetchOnMount es una herramienta sencilla que fuerza una verificación de actualidad cada vez que se carga el componente responsable de las consultas, sin necesidad de incluir un botón manual de actualización.

El problema

Considere dos rutas que comparten un mismo recurso del servidor:

  • Página de usuarios — Muestra cada fila de usuario proveniente de un endpoint de lista.
  • Página de edición de usuarios — Guarda los cambios realizados en un único usuario.

La ruta de la lista suele tener este aspecto:

const { data } = useQuery({
  queryKey: ["users"],
  queryFn: getUsers,
});

El flujo normal parece funcionar bien hasta que alguien edita una fila, la guarda y vuelve. La mutación tuvo éxito en el servidor, pero la tabla sigue mostrando los valores anteriores. La pregunta es por qué la interfaz de usuario no registró el cambio.

¿Por qué ocurre esto?

React Query almacena las respuestas exitosas bajo un queryKey. Salir de una página y volver no garantiza que se envíe una nueva solicitud. La biblioteca verifica si la clave ya contiene datos; si es así, ese estado se muestra de inmediato.

La ventaja en velocidad es real, pero el inconveniente es que los datos quedan obsoletos cada vez que el caché y el servidor difieren. Las causas más comunes incluyen:

  • Otro componente modificó el mismo recurso.
  • Otra ruta ejecutó una mutación.
  • Otra pestaña del navegador cambió los datos.
  • Un tercero actualizó el backend.

Mientras algo no invalide o vuelva a cargar la clave, la interfaz sigue confiando en el caché.

Un ejemplo real

Un árbol de rutas compacto se ve así:

Users
 ├── User List
 └── Edit User

La página de lista carga a los usuarios con:

const { data } = useQuery({
  queryKey: ["users"],
  queryFn: fetchUsers,
});

La página de edición mantiene los datos con:

await updateUser(userId, values);

Luego vuelve a la lista:

navigate("/users");

Después de esa navegación, la tabla sigue pudiendo renderizarse:

John
Alice
Michael

aunque el servidor ahora almacena:

Johnny

React Query simplemente reutilizó el contenido de la lista anterior para ["users"].

Soluciones tradicionales

A menudo, los equipos fuerzan una actualización manual después de una escritura exitosa:

queryClient.invalidateQueries({
  queryKey: ["users"],
});

o

queryClient.refetchQueries({
  queryKey: ["users"],
});

La invalidación y la recarga explícita siguen siendo las herramientas adecuadas justo después de realizar una mutación en el componente correspondiente. Sin embargo, no son suficientes cuando es necesario recuperar la actualidad de los datos tras una navegación, tareas en segundo plano o actualizaciones que ocurrieron fuera del árbol de componentes actual. En esos casos, se desea que la consulta verifique con el servidor cuando la página se vuelva a cargar.

Introducir refetchOnMount

La opción lleva este nombre literalmente:

refetchOnMount

Indica a la biblioteca que realice una nueva solicitud cada vez que se cargue el componente que contiene la consulta. La consulta de lista pasa a ser:

const { data } = useQuery({
  queryKey: ["users"],
  queryFn: fetchUsers,
  refetchOnMount: true,
});

La secuencia es entonces la siguiente:

  1. Abrir la página de Usuarios.
  2. Guardar en caché la respuesta.
  3. Editar un registro en otro lugar.
  4. Navegar de vuelta a la página de Usuarios.
  5. Cargar nuevamente el componente de lista.
  6. React Query solicita automáticamente un nuevo conjunto de datos.

No hay control manual de actualización, no se vuelve a cargar toda la página, y no existe una solicitud ad hoc de recarga oculta en los manejadores de navegación.

Antes y después

Sin refetchOnMount

Open Users
      ↓
Data Cached
      ↓
Edit User
      ↓
Back to Users
      ↓
Old Cached Data

Con refetchOnMount

Open Users
      ↓
Data Cached
      ↓
Edit User
      ↓
Back to Users
      ↓
Component Mounts
      ↓
Automatic Refetch
      ↓
Fresh Updated Data

Ejemplo completo

Comience con la importación del hook:

import { useQuery } from "@tanstack/react-query";

Un componente de lista que siempre vuelve a validar al montarse:

const Users = () => {
  const { data, isLoading } = useQuery({
    queryKey: ["users"],
    queryFn: fetchUsers,
    refetchOnMount: true,
  });  if (isLoading) {
    return <p>Loading...</p>;
  }  return (
    <div>
      {data?.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}
    </div>
  );
};

Cada visita a esa página solicita al servidor las filas más recientes en lugar de confiar únicamente en la caché.

¿Debería usarlo siempre?

No. Cuando cada mutación invalida cuidadosamente las claves relacionadas, la recarga al montarse puede resultar redundante.

Aún así es útil cuando:

  • Varias pantallas modifican el mismo recurso.
  • Los usuarios cambian frecuentemente de ruta.
  • Los datos cambian fuera del componente montado.
  • La interfaz debe mantenerse cercana a la realidad del servidor.
  • Se aceptan llamadas adicionales ocasionales a la red.
  • Para recursos que cambian con frecuencia, habilitar esta opción es una forma económica de reducir las visualizaciones obsoletas.

    Cuándo es útil

    Este patrón es adecuado para herramientas de back-office multi-pantalla como:

    • Consolas que gestionan cuentas y roles
    • Editores de catálogos para mercancías
    • Pantallas de inventario y almacén
    • Consolas para operadores internos
    • Flujos de trabajo de procesamiento de pedidos y compras
    • Espacios de trabajo para la gestión de relaciones
    • Centros de autoservicio para el personal

    Estos productos suelen editar un único conjunto de datos a través de varias vías, por lo que la recarga automática al cargar mantiene las vistas de lista actualizadas con los cambios más recientes.

    Consideraciones finales

    El caché es una de las principales fortalezas de React Query, y es el mismo caché el que permite que las filas obsoletas permanezcan después de la navegación. Al establecer refetchOnMount, se indica a la biblioteca que vuelva a consultar el servidor cada vez que la página se carga nuevamente.

    Considérelo como una red de seguridad, no como un sustituto de la invalidación. Después de realizar una mutación que usted controla, primero invalide o actualice las consultas afectadas. Utilice mount refetch en los casos en que otra pantalla, pestaña o proceso pueda haber modificado los datos sin que su gestor de mutaciones local se dé cuenta.

    Lecturas relacionadas

  • Configurar un frontend de React con Node, npm y Vite — Asignar herramientas al estilo de Python a una pila de React más Vite: instalar Node, ignorar node_modules, crear la estructura básica con Vite y ejecutar el servidor de desarrollo local.
  • Coordinar subidas múltiples en tablas con la API Web Locks — Evitar subidas duplicadas y reanudables entre pestañas del navegador reemplazando los trucos con localStorage y BroadcastChannel por navigator.locks y un coordinador de subidas en React.
  • Usar DHTMLX React Gantt con Remix para aplicaciones de planificación de proyectos — Integrar DHTMLX React Gantt en las rutas de Remix con una configuración estable, callbacks data.save y acceso opcional a la API imperativa, sin soluciones alternativas de SSR.