Service status

A graft mounted on a TanStack Query. Two regions are two providers with their own cache key, and an injected effect polls faster while something is down.

eu
checking…
us
checking…

Mounted

The same graft twice, with a different region. Two providers, two cache keys, two independent states — and only the degraded one keeps checking.

tsx
// -components/services_demo.tsx
export const ServicesDemo = () => (
  <QueryClientProvider client={client}>
    <GraftServices.Provider region="eu">
      <ServicesPanel />
    </GraftServices.Provider>

    <GraftServices.Provider region="us">
      <ServicesPanel />
    </GraftServices.Provider>
  </QueryClientProvider>
);

The hook is a query

graft takes a hook, and useQuery is a hook. The provider prop becomes part of the cache key, and what the graft returns is the shape the feature wants to expose, not the shape the query happens to have.

tsx
// -constants/graft_services.ts
export const GraftServices = createGraft({
  name: "GraftServices",
  graft: useGraft,
  inject: [useInjectEscalate],
});

function useGraft({ region }: { region: Region }) {
  const query = useQuery({
    queryKey: ["services", region],
    queryFn: () => fetchServices(region),
    staleTime: 10_000,
  });

  const services = query.data ?? [];

  return {
    region,
    services,
    isDown: services.some((service) => service.status === "down"),
    isPending: query.isPending,
    isFetching: query.isFetching,
    refetch: query.refetch,
  };
}

Which is the answer to the obvious question. Calling useQuery in the component would work: every component that needs the data repeats the key, the options and the derivation, and gets no place to put anything that is not rendering.

The rule that escalates

Polling faster during an incident is a rule about the feature, not about a panel. Injected, it runs wherever the provider is mounted and stops with it — no component decides to start it, and none can forget to.

tsx
// while something is down, ask more often
function useInjectEscalate({ isDown, refetch }: { isDown: boolean; refetch: () => void }) {
  useEffect(() => {
    if (!isDown) return;

    const interval = setInterval(() => refetch(), ESCALATED_INTERVAL);

    return () => clearInterval(interval);
  }, [isDown, refetch]);
}

What the components see

A flat object. No query key, no client, no idea that a poll ever accelerated.

tsx
// -components/services_panel.tsx
export const ServicesPanel = () => {
  const { isDown, isFetching, isPending, refetch, region, services } = GraftServices.use();

  return (
    <Card>
      <span>{region}</span>
      {isFetching && <Spinner />}
      …
    </Card>
  );
};