## Invalidation You’ve made a mutation and now your page contains stale data. Some patterns that you might find yourself doing is: - Fully refreshing the page - Passing down callbacks to refetch data when the mutation happens - Leaving it stale These aren’t good options because they sacrifice code quality, load times or user experience. The best thing to do is invalidation: record that a piece of data is stale and let the consumer of that data fetch it the next time it needs it. If you’re not using [TanStack Query](https://tanstack.com/query/latest) or one of its many derivatives, you should be. It is a near-perfect abstraction for client side fetching, caching and mutation. For me, every roll-your-own data fetching code I’ve ever written always inevitably evolves into worse version of TanStack Query so please, do yourself a favour and just use it from the start. ## Invalidation across windows If your users are likely to have multiple tabs open, you need to consider how to invalidate data across windows. By default in TanStack Query, query caches are local to the tab because they are stored in memory. This means that if you make a change in one tab, the other tabs won’t know about it and will continue to display stale data. The best way to handle this is use a [`BroadcastChannel`](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) to send a message to all other tabs when a mutation happens. This message can be picked up by the other tabs and used to invalidate the relevant data. ## Synced invalidation Normal invalidation has an important limitation: if some other user makes a change, you don’t know that change has been made and therefore you don’t know you need to invalidate the data. The idea of the synced invalidation is a very low impact implementation of a real-time data layer. Often a “real-time” requirement leads to a complicated and high development impact websocket based sync system that broadcasts all data to every online user, pushing local mutations and receiving changes locally that need to be injected and updated in a state layer. Synced invalidation is a simpler concept: let all clients know that a resource has been invalidated and utilise the same logic, structure and cache layer that exists for when a change has been made locally. This is sometimes called a poke-and-pull or a poke-and-poll, eluding to its poll-like nature but with a key efficiency that make it useful in the real world. - Don’t use this too much. If you use this on unnecessary invalidations and have a lot of active users you can create a very spiky traffic pattern. Instead of requests being made evenly over time, all active clients will request new data at once. - Don’t be tempted to add the efficiency of “sending the updated data with the poke”. You then need to apply authentication, roles, authorisation, permissions, security, etc to the stream and selectively send data to different users. The beauty of the synced invalidation is that it doesn’t matter if the client tries to invalidate a resource that it hasn’t or can’t access because invalidation isn’t fetching. If you need a more heavy duty solution, go for the whole shebang. ## The whole shebang If you feel that you need something more real-time, more efficient or more collaborative you should use probably reach to something local-first oriented like [Replicache](https://replicache.dev) or [WatermelonDB](https://watermelondb.dev/docs). This is the point at which you’ll need to start changing the backend implementation to align with these models. These technologies and concepts are incredibly powerful but my only advice is to get everyone onboard and give in to the paradigm. Doing a half arsed implementation is by far the worst of both worlds.