Nakakaligtas ang tags sa rename, ang keys hindi
Nag-a-scale sa mga team ang declarative tags. Hindi ang string-based keys.
Mas maikli, mas magaan, at masarap basahin ang keys ng TanStack Query sa loob ng iisang codebase. Para sa isang feature team na nagmamay-ari ng bawat query, ang key-based API ang halatang pili. Ang tag system ng RTK Query ay nagdadagdag ng hakbang na hindi mo kailangan sa ganyang laki.
Ang hugis na umuubra para sa isang team ay nagiging liability kapag tumawid ito sa boundaries ng mga team. Ang failure mode, lumilipat mula sa “ayusin bago mag-merge” tungo sa “malalaman mo na lang sa isang support ticket.”
Isang order, dalawang team
Nagshi-ship ang orders team ng isang placeOrder mutation. May getProduct query ang catalogue team na nagbabalik ng detalye at stock ng isang item. Kapag nagtagumpay ang order, stale na ang naka-cache na product (kababago lang ng stock nito), at kailangang may mag-mark dito para ma-refetch.
Gamit ang RTK Query tags
Idineklara ng catalogue team kung ano ang hawak ng query nila:
getProduct: builder.query({
query: (id) => `/products/${id}`,
providesTags: ['Product'],
}),
Idineklara ng orders team kung ano ang naaapektuhan ng mutation nila:
placeOrder: builder.mutation({
query: (order) => ({ url: '/orders', method: 'POST', body: order }),
invalidatesTags: ['Product'],
}),
Kapag nagtagumpay ang mutation, hinahanap ng library sa cache nito ang mga query na nagbibigay ng Product tag, at nire-refetch ang mga naka-mount sa ngayon. Hindi kailanman binabasa ng orders team ang code ng catalogue. Hindi nito kailangang malaman kung anong query key ang ginagamit ng catalogue o kung anong hugis ang cache entry. Idinedeklara nito ang intent sa categorical level at ang library na ang bahala sa pag-uugnay.
Nakakabit ang parehong team sa string na 'Product'. Ang coupling na ‘yan ay nasa isang shared na tagTypes list na idineklara sa API module, kaya may iisang source of truth ito.
Gamit ang TanStack Query keys
Nag-i-invalidate ang TanStack ayon sa key, hindi ayon sa category. Ganito ang isinulat ng orders team:
queryClient.invalidateQueries({ queryKey: ['product'] });
Para maging tama ang linyang ‘yan, kailangang alam ng orders team ang eksaktong hugis ng query key ng catalogue team. Pumupunta sila sa code ng catalogue, hinahanap ang useQuery call, binabasa ang key, at kinokopya ito sa sarili nilang invalidation.
Nakakabit ang mga team sa parehong string na 'product', pero nasa ibang lugar ang coupling. Isa itong magic string sa mutation handler ng orders team, na walang contract na tumuturo pabalik sa query ng catalogue.
Ano ang nangyayari kapag naghiwalay ang mga team
Parehong resulta ang nabubuo ng dalawang approach kapag nananatiling coordinated ang mga team. Nire-refetch ang naka-cache na product, nag-a-update ang UI, nakikita ng user ang bagong stock. Naghihiwalay ang dalawang approach kapag lumuwag ang coordination.
Halimbawa: isang rename. Nagre-refactor ang catalogue team. Nagbago ang domain term. Ang dating tinatawag nilang “product” ay tinatawag na ngayong “listing” sa buong API, sa docs, at sa pang-araw-araw na wika ng team. Pinalitan nila ang pangalan ng query key:
// before
useQuery({ queryKey: ['product', productId], queryFn: fetchProduct });
// after
useQuery({ queryKey: ['listing', listingId], queryFn: fetchListing });
Nag-ship sila.
Sa mundo ng RTK Query, kung saan tags ang gamit, walang epekto ang rename sa invalidation ng orders team. Independent ang tags sa query keys. Ang query ng catalogue team ay nagbibigay pa rin ng 'Product'. Ang mutation ng orders team ay nag-i-invalidate pa rin ng 'Product'. Buo pa rin ang koneksyon.
Sa mundo ng TanStack Query, kung saan keys ang gamit, tahimik na sinisira ng rename ang orders team. Ang invalidateQueries({ queryKey: ['product'] }) ay tumutugma na ngayon sa zero na cached queries. Nagtagumpay ang mutation. Hindi naglalabas ng error ang library dahil hindi error ang zero matches. Nananatiling stale ang product page ng user hanggang sa umalis siya sa screen at bumalik, o hanggang sa lumitaw ang bug sa isang support ticket.
Walang type error. Walang compile failure. Walang runtime exception. Stale na UI sa production.
Saan nakalagay ang coupling
Parehong coupling sa pagitan ng dalawang team ang ini-encode ng dalawang approach. Ang pagkakaiba ay kung saan naroon ang coupling, at kung paano ito napapansin kapag nasira.
Pinag-uugnay ng tags ang mga team sa pamamagitan ng isang category name: isang abstract noun na naglalarawan ng uri ng data. Nasa isang shared na enum ito. Ang mga rename ay nangangailangan ng coordination sa enum na ‘yan, at lumilitaw ang rename sa compile time: sa loob ng iisang createApi module, agad-agad; sa mga app na hiwa-hiwalay na nagshi-ship, sa susunod na build ng bawat app gamit ang na-update na shared package.
Pinag-uugnay ng keys ang mga team sa pamamagitan ng isang string identifier: ang literal na hugis na kumikilala sa isang cached entry. Naroon ito kung saan man ito i-type ng isang tao. Hindi nangangailangan ng coordination ang mga rename dahil walang nagpapatupad nito. Saka lang sila napapansin kapag tumama na ang bug sa production.
Wala sa dalawang behaviour ang nakaukit sa mga salitang “tag” at “key”. Puwedeng mag-hardcode ang isang team ng tag string sa labas ng enum, at puwedeng gumawa ang isang TanStack team ng shared at typed na key factories na magpapahalata ng mga rename nang kasing-bilis. Galing ang garantiya sa shared contract, at ang pagkakaiba ay kung saan ka itinutulak ng bawat API: humihingi ang RTK Query ng tags mula sa dineklarang tagTypes list, kaya ang contract ang pinakamadaling daan; tumatanggap ang TanStack ng kahit anong array, kaya ang contract ay kailangan mong itayo at bantayan mag-isa.
Ang gap na ‘yan sa paglitaw ay hindi isang depekto sa disenyo ng TanStack Query. Mas maikli, mas magaan, at bagay na bagay ang key-based API sa isang team na kabisado ang bawat query. Hindi na kasya ang hugis kapag ang mga taong nagsusulat ng invalidation at ang mga taong nagsusulat ng query ay hindi na iisang grupo ng tao.
Alin ang bagay sa team mo
Isang team, isang codebase. Kung ganyan ang app mo, halos aesthetic lang ang pagkakaiba. Mas maikli ang key-based API ng TanStack at walang idinadagdag na hakbang. Maliit ang panganib ng tahimik na invalidation drift dahil may buo kang visibility sa bawat query key.
Maraming team na nagshi-ship nang independent. Dito nagsisimulang mag-compound ang failure mode ng key-based invalidation. Puwedeng tahimik na makasira ang refactor ng bawat team sa kahit anong ibang team na tumutukoy sa keys nila. Puwede kang gumawa ng conventions para pagaanin ‘yan (query key factories, shared key constants, code review checklists, integration tests sa buong features), pero conventions ‘yan, hindi enforcement: itinatayo mo ulit ang ibinibigay na sa’yo ng tag system nang libre.
Bukas pa ang library choice, at may paparating na federation o multi-team na trabaho. Sa ganyang kaso, sulit na maintindihan ang tag system bago pa magmukhang arbitrary ang API shape. Ang pagpili sa pagitan ng dalawang library ay ang pagpili kung anong failure modes ang handa mong tanggapin.
Binabalikan ng Module Federation series ang mas malawak na tanong ng state management sa mga independiyenteng na-ship na remote, sa Isang shared store para sa panig ng server at sa Client state sa kabila ng seam para sa panig ng client. Kung bago ka sa server-vs-client-state split na ipinapalagay nito, magsimula rito.