Tags de RTK Query vs query keys de TanStack Query

Tags vs query keys: una petita diferència d'API que canvia com es coordinen els equips

Les tags sobreviuen a un rename, les keys no

Les tags declaratives escalen a diversos equips. Les keys basades en strings no.

Les keys de TanStack Query són més curtes, més lleugeres i agradables de llegir dins d’un sol codebase. Per a un equip de feature que gestiona totes les queries, l’API basada en keys és la tria òbvia. El sistema de tags de RTK Query afegeix una cerimònia que no necessites a aquesta escala.

La forma que funciona per a un equip es converteix en un llast quan travessa les fronteres entre equips. El mode de fallada passa d’«arregla-ho abans del merge» a «troba-ho des d’un tiquet de suport».

Una comanda, dos equips

L’equip de comandes publica una mutation placeOrder. L’equip de catàleg té una query getProduct que retorna els detalls i l’estoc d’un article. Quan la comanda té èxit, el producte al cache està caducat (l’estoc acaba de canviar), i alguna cosa ha de marcar-lo perquè es torni a demanar.

Amb les tags de RTK Query

L’equip de catàleg declara què conté la seva query:

getProduct: builder.query({
  query: (id) => `/products/${id}`,
  providesTags: ['Product'],
}),

L’equip de comandes declara què afecta la seva mutation:

placeOrder: builder.mutation({
  query: (order) => ({ url: '/orders', method: 'POST', body: order }),
  invalidatesTags: ['Product'],
}),

Quan la mutation té èxit, la biblioteca recorre el seu cache, troba les queries que proveeixen la tag Product, i torna a demanar les que estan muntades en aquell moment. L’equip de comandes no llegeix mai el codi del catàleg. No necessita saber quina query key fa servir el catàleg ni quina forma té l’entrada del cache. Declara la intenció a un nivell categòric i la biblioteca ho connecta.

Tots dos equips estan acoblats a l’string 'Product'. Aquest acoblament viu en una llista tagTypes compartida i declarada al mòdul de l’API, així que té una sola font de veritat.

Amb les query keys de TanStack Query

TanStack invalida per key, no per categoria. L’equip de comandes escriu:

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

Perquè aquesta línia sigui correcta, l’equip de comandes ha de saber la forma exacta de la query key de l’equip de catàleg. Miren el codi del catàleg, troben la crida a useQuery, llegeixen la key, i la copien a la seva pròpia invalidació.

Els equips estan acoblats al mateix string 'product', però l’acoblament viu en un lloc diferent. És un magic string al handler de la mutation de l’equip de comandes, sense cap contracte que apunti a la query del catàleg.

Què passa quan els equips es desincronitzen

Tots dos enfocaments produeixen el mateix resultat quan els equips es mantenen coordinats. El producte al cache es torna a demanar, la UI s’actualitza, l’usuari veu l’estoc nou. Els enfocaments divergeixen quan la coordinació falla.

Posem per cas un rename. L’equip de catàleg està refactoritzant. El terme del domini ha canviat. El que abans anomenaven «product» ara es diu «listing» a l’API, a la documentació, i al llenguatge del dia a dia de l’equip. Reanomenen la query key:

// before
useQuery({ queryKey: ['product', productId], queryFn: fetchProduct });

// after
useQuery({ queryKey: ['listing', listingId], queryFn: fetchListing });

Ho publiquen.

En un món de RTK Query amb tags, el rename no té cap efecte sobre la invalidació de l’equip de comandes. Les tags són independents de les query keys. La query de l’equip de catàleg segueix proveint 'Product'. La mutation de l’equip de comandes segueix invalidant 'Product'. La connexió aguanta.

En un món de TanStack Query amb keys, el rename trenca l’equip de comandes en silenci. invalidateQueries({ queryKey: ['product'] }) ara coincideix amb zero queries al cache. La mutation té èxit. La biblioteca no mostra cap error perquè trobar zero coincidències no n’és cap. La fitxa de producte de l’usuari es queda caducada fins que l’usuari surt de la pantalla i hi torna, o fins que un tiquet de suport treu el bug a la llum.

Cap error de tipus. Cap fallada de compilació. Cap excepció en runtime. UI caducada en producció.

On viu l’acoblament

Tots dos enfocaments codifiquen el mateix acoblament entre els dos equips. La diferència és on viu l’acoblament, i com es nota quan es trenca.

Les tags acoblen els equips a través d’un nom de categoria: un nom abstracte que descriu una mena de dades. Viu en un enum compartit. Els renames demanen coordinació sobre aquest enum, i es fan visibles en compilar: dins d’un mateix mòdul createApi, a l’instant; entre apps que es despleguen per separat, a la següent build de cada app contra el paquet compartit actualitzat.

Les keys acoblen els equips a través d’un identificador de string: la forma literal que identifica una entrada del cache. Viu allà on algú l’escriu. Els renames no necessiten coordinació perquè res no els obliga. Apareixen quan el bug arriba a producció.

Cap dels dos comportaments no ve gravat a les paraules «tag» i «key». Un equip pot hardcodejar l’string d’una tag fora de l’enum, i un equip de TanStack pot muntar factories de keys compartides i tipades que facin sonar els renames igual de fort. La garantia surt del contracte compartit, i la diferència és cap a on empeny cada API: RTK Query demana tags d’una llista tagTypes declarada, així que el contracte és el camí de menys esforç; TanStack accepta qualsevol array, així que el contracte és una cosa que has de construir i vigilar tu.

Aquesta diferència en el moment d’aparèixer no és un defecte del disseny de TanStack Query. L’API basada en keys és més curta, més lleugera, i s’adapta bé a un sol equip que té totes les queries al cap. La forma deixa d’encaixar quan la gent que escriu la invalidació i la gent que escriu la query deixen de ser la mateixa gent.

Quina encaixa amb el teu equip

Un equip, un codebase. Si aquesta és la teva app, la diferència és sobretot estètica. L’API basada en keys de TanStack és més curta i no afegeix cap cerimònia. El risc de desincronització silenciosa de la invalidació és petit perquè tens visibilitat total sobre cada query key.

Diversos equips que despleguen de forma independent. Aquí el mode de fallada de la invalidació basada en keys comença a acumular-se. El refactor de cada equip és una possible ruptura silenciosa per a qualsevol altre equip que hagi referenciat les seves keys. Pots construir convencions per suavitzar-ho (query key factories, constants de key compartides, checklists de revisió de codi, tests d’integració entre features), però són convencions, no imposició: estàs reconstruint el que el sistema de tags et dona de franc.

Una tria de biblioteca encara oberta, amb federació o feina entre equips a l’horitzó. En aquest cas val la pena entendre el sistema de tags abans que la forma de l’API et sembli arbitrària. Triar entre les dues biblioteques vol dir triar amb quins modes de fallada estàs disposat a conviure.

La sèrie de Module Federation reprèn la pregunta més àmplia de la gestió d’estat entre remotes desplegats de forma independent, a Un sol store compartit per a la meitat de servidor i a L’estat de client creua la frontera per a la de client. Si encara no coneixes la distinció entre estat del servidor i estat del client que aquest post dona per feta, comença aquí.

Warren de Leon
Warren de Leon

Software Engineering Manager. Recentment he liderat l'equip de Mobile Platform a Hargreaves Lansdown. Escric sobre lideratge tècnic, React Native i com construir bons equips.

Veure perfil