A tale of refactoring legacy code with react-query
The team's existing API call structure was riddled with global state and useEffect. Loading logic was duplicated everywhere, and without any caching—even polling was manual—the server load became absurd. So over the past three weeks, I worked on replacing it entirely with react-query.
The work roughly went like this:
1. Wrapped existing API functions as query hooks and validated return types with zod
2. Extracted loading/error states into common components
3. Only converted parts needing optimistic updates to useMutation
4. Adjusted refetch intervals per screen to eliminate over-fetching
The hardest part was designing cache keys. Filter values depend on the query string, and if the keys weren't set up properly, the data got mixed up all day—I ended up spending two days just debugging. In the end, I created a convention document and extracted a key factory as a shared function.
As a result, loading spinner code was reduced by 70%, and server request counts dropped by more than half. It was something I'd put off for months, but it was definitely worth tackling even on a weekend.
7 answers
Agreed. react-query handles loading and cache all with this one thing—literally a whole new world.
Oh, I didn't know about this. The Key Factory convention doc is really good lol. Our team should try following this too.
Well, I'm not sure... Wouldn't it be more important for the whole team to understand the legacy code than to introduce a library?
I had a similar surgery myself, and the cache key is really the core. But wouldn't adding zod make the learning curve even steeper? If it's a full replacement in just a few weeks, the team probably had a hard time adapting.
Impressive that the number of server requests has been halved. By the way, when adjusting the refetch interval per screen, you should also look at staleTime and gcTime together.
Making the key factory put an end to all the suffering lol. I didn't make it either, and every time I changed the filter on the same page, the data got tangled up and I lost my mind.
That's right lol. If you manage server data with global state, it won't work at all.