Tags de RTK Query vs query keys de TanStack Query

Tags vs query keys: una pequeña diferencia de API que cambia cómo se coordinan los equipos

La conclusión primero

Los tags declarativos escalan a varios equipos. Las keys basadas en strings no. Esa es la comparación en una línea, y el resto del post es la prueba.

Las keys de TanStack Query son más cortas, más ligeras y agradables de leer dentro de un solo codebase. Para un equipo de feature que posee todas las queries, la API basada en keys es la elección obvia. El sistema de tags de RTK Query añade una ceremonia que no necesitas a ese tamaño.

La forma que funciona para un equipo se convierte en un lastre al cruzar las fronteras entre equipos. El modo de fallo pasa de “arréglalo antes del merge” a “encuéntralo desde un ticket de soporte”.

El escenario

El equipo de trading publica una mutación executeTrade. El equipo de portfolio tiene una query getPortfolio que devuelve las posiciones del usuario. Cuando la operación tiene éxito, la caché de portfolio queda obsoleta, y algo tiene que marcarla para refetch.

Con tags de RTK Query

El equipo de portfolio declara lo que contiene su query:

getPortfolio: builder.query({
  query: (id) => `/portfolio/${id}`,
  providesTags: ['Portfolio'],
}),

El equipo de trading declara lo que afecta su mutación:

executeTrade: builder.mutation({
  query: (order) => ({ url: '/trades', method: 'POST', body: order }),
  invalidatesTags: ['Portfolio'],
}),

Cuando la mutación tiene éxito, la librería recorre su caché, encuentra las queries que proveen el tag Portfolio y hace refetch de las que están montadas en ese momento. El equipo de trading nunca lee el código de portfolio. No necesita saber qué query key usa portfolio ni qué forma tiene la entrada de caché. Declara su intención a un nivel de categoría y la librería lo conecta.

Los dos equipos están acoplados al string 'Portfolio'. Ese acoplamiento vive en una lista tagTypes compartida y declarada en el módulo de la API, así que tiene una única fuente de verdad.

Con query keys de TanStack Query

TanStack invalida por key, no por categoría. El equipo de trading escribe:

queryClient.invalidateQueries({ queryKey: ['portfolio'] });

Para que esa línea sea correcta, el equipo de trading tiene que conocer la forma exacta de la query key del equipo de portfolio. Va a mirar el código de portfolio, encuentra la llamada a useQuery, lee la key y la copia en su propia invalidación.

Los equipos están acoplados al mismo string 'portfolio', pero el acoplamiento vive en otro sitio. Es un string mágico en el handler de la mutación del equipo de trading, sin ningún contrato que apunte de vuelta a la query de portfolio.

Qué pasa cuando los equipos se desincronizan

Los dos enfoques producen el mismo resultado cuando los equipos siguen coordinados. Los datos de portfolio en caché hacen refetch, la UI se actualiza, el usuario ve posiciones frescas. Los enfoques divergen cuando la coordinación se afloja.

Pon por caso un rename. El equipo de portfolio está refactorizando. El término del dominio ha cambiado. Lo que antes llamaban “portfolio” ahora se llama “holdings” en toda la API, en la documentación y en el lenguaje del día a día del equipo. Renombran la query key:

// before
useQuery({ queryKey: ['portfolio', accountId], queryFn: fetchPortfolio });

// after
useQuery({ queryKey: ['holdings', accountId], queryFn: fetchHoldings });

Lo publican.

En un mundo de RTK Query con tags, el rename no afecta a la invalidación del equipo de trading. Los tags son independientes de las query keys. La query del equipo de portfolio sigue proveyendo 'Portfolio'. La mutación del equipo de trading sigue invalidando 'Portfolio'. La conexión aguanta.

En un mundo de TanStack Query con keys, el rename rompe al equipo de trading en silencio. invalidateQueries({ queryKey: ['portfolio'] }) ahora coincide con cero queries en caché. La mutación tiene éxito. La librería no muestra ningún error porque encontrar cero coincidencias no lo es. La caché de portfolio del usuario se queda obsoleta hasta que sale de la pantalla y vuelve, o hasta que un ticket de soporte destapa el bug.

Sin error de tipos. Sin fallo de compilación. Sin excepción en runtime. UI obsoleta en producción.

Dónde vive el acoplamiento

Los dos enfoques codifican el mismo acoplamiento entre los dos equipos. La diferencia está en dónde vive ese acoplamiento, y en qué aparece cuando se rompe.

Los tags acoplan a los equipos a través de un nombre de categoría: un sustantivo abstracto que describe un tipo de datos. Vive en un enum compartido. Los renames necesitan coordinación a través de ese enum, y el rename aparece enseguida porque cada endpoint que referencia el nombre antiguo queda inválido de golpe.

Las keys acoplan a los equipos a través de un identificador de string: la forma literal que identifica una entrada en caché. Vive donde sea que alguien lo escriba. Los renames no necesitan coordinación porque nada la fuerza. Aparecen cuando el bug llega a producción.

Esa diferencia en cuándo aparece el fallo no es un defecto del diseño de TanStack Query. La API basada en keys es más corta, más ligera y encaja bien en un solo equipo que tiene todas las queries en la cabeza. La forma deja de encajar cuando las personas que escriben la invalidación y las personas que escriben la query dejan de ser las mismas.

Qué significa esto en la práctica

Algunas cosas que sacar de aquí.

Si tu app es un solo equipo y un solo codebase, la diferencia es sobre todo estética. La API basada en keys de TanStack es más corta y no añade ceremonia. El riesgo de una desincronización silenciosa en la invalidación es pequeño porque tienes visibilidad completa de cada query key.

Si tu app tiene varios equipos y despliegan de forma independiente, el modo de fallo de la invalidación basada en keys empieza a acumularse. El refactor de cada equipo es una posible rotura silenciosa para cualquier otro equipo que haya referenciado sus keys. Puedes construir convenciones para suavizarlo (factories de query keys, constantes de key compartidas, checklists de code review, tests de integración entre features), pero eso son convenciones, no una garantía forzada: estás reconstruyendo lo que el sistema de tags te da gratis.

Si estás al principio de una elección de librería y tienes federación o coordinación multiequipo en el horizonte, vale la pena entender el sistema de tags antes de que la forma de la API te parezca arbitraria. Elegir entre las dos librerías significa elegir con qué modos de fallo estás dispuesto a vivir.

La serie de Module Federation retoma la pregunta más amplia de la gestión de estado entre remotes desplegados de forma independiente cuando lleguen sus posts sobre estado. Si eres nuevo en la separación entre estado de servidor y estado de cliente que este post da por supuesta, empieza aquí.

Warren de Leon
Warren de Leon

Software Engineering Manager. Recientemente lideré el equipo de Mobile Platform en Hargreaves Lansdown. Escribo sobre liderazgo técnico, React Native y cómo construir buenos equipos.

Ver perfil