Skip to main content

2 posts tagged with "react-query"

View All Tags

react-query stops at the browser. alova/server handles your BFF.

· 4 min read
Alova Team

You built the frontend on react-query. Its cache and retry keep the browser happy. Then you stood up a Node BFF that calls three downstream services, and the retries and throttling for those calls live on the server. react-query never runs there. This post shows the exact line where react-query's job ends and where alova/server picks up, with the code for each side.

The line

react-query lives in the browser. Its useQuery retry, its cache, its dedup, all happen per browser tab, bound to React's render cycle. None of that executes inside your BFF when your BFF calls a downstream. So the question isn't "react-query or alova". It's "who handles the server-side calls".

Retry: browser vs BFF

react-query retries a failed query in the browser:

useQuery({
queryKey: ['resource', id],
queryFn: () => fetch(`/api/resource/${id}`).then(r => r.json()),
retry: 3,
retryDelay: attempt => Math.min(1000 * 2 ** attempt, 8000)
});

That retry protects the user's view. It does nothing for the BFF's outbound call to the downstream, because that call doesn't go through react-query.

On the BFF, alova/server retries the outbound request with backoff:

const { createAlova } = require('alova');
const { axiosRequestAdapter } = require('@alova/adapter-axios');
const { retry } = require('alova/server');

const alovaInst = createAlova({
baseURL: 'https://downstream.internal',
requestAdapter: axiosRequestAdapter()
});

const getResource = (id) =>
retry(alovaInst.Get(`/resource/${id}`), {
retry: 5,
backoff: { delay: 1000, multiplier: 2 }
});

// inside your route handler:
const data = await getResource(req.params.id);

Same idea, different layer. react-query covers the browser; retry covers the server.

Rate limiting: only on the server

react-query has no concept of throttling your BFF's calls to a downstream. There's nothing in its API for "max 4 requests per 4 seconds to service X". That is a server-side concern, and alova/server's createRateLimiter is built for it:

const { createRateLimiter } = require('alova/server');

const rateLimit = createRateLimiter({ duration: 4000, points: 4 });

app.get('/api/resource/:id', async (req, res) => {
try {
const data = await rateLimit(
retry(alovaInst.Get(`/resource/${req.params.id}`), {
retry: 5,
backoff: { delay: 1000, multiplier: 2 }
}),
{ key: `downstream:${req.params.id}` }
);
res.json(data);
} catch (err) {
res.status(429).json({ error: 'downstream busy, retry later' });
}
});

rateLimit consumes a point before the call leaves, so a struggling downstream isn't buried by your own traffic. The default store is the method's l2Cache; across instances you swap in a shared one (@alova/psc or redis) so the limit is real cluster-wide.

Cache: know which side it lives on

This is the part people mix up. react-query's cache is per browser. It keeps a user from refetching the same resource in the same tab. It does nothing for your BFF hammering a slow downstream, because that call isn't in the browser.

alova's caching is a client-side strategy feature too. cacheFor controls how long a method response is kept, with modes memory and restore, and non-GET requests default to null (no cache). On the server, alova/server gives you retry and createRateLimiter; it does not hand you a server-side response cache for downstream calls. If you want to skip a slow downstream for repeated GETs, you add your own cache (or lean on the downstream's own), and layer retry/rateLimit on top.

So the split is clean: react-query owns the browser cache, alova/server owns the BFF's outbound retry and throttle. Neither steps on the other.

The two tools solve different layers. Use react-query where the request ends in the browser, and alova/server for the BFF. For the full选型 view, see the react-query vs alova comparison.

react-query or alova: does the request leave the browser?

· 3 min read
Alova Team

Choosing a data-fetching library usually starts with "which cache is better". That question skips the part that actually bites later: where do your requests run?

If every call lives in the browser and you're on React, react-query is a mature, well-trodden pick. But the moment you need the same request logic on a phone that isn't React Native, or inside a BFF that calls downstream services, the map changes. alova puts those cases on the same API. This post is a straight comparison, including where alova is the weaker choice.

Where react-query is clearly ahead

Be honest first:

  • React fit. react-query is built around React's render model. Hooks like useQuery slot into components naturally, and its devtools and query window are the most polished in the space.
  • Caching maturity. Its cache, dedup, background refetch, and stale-while-revalidate behavior are battle-tested across a huge number of production apps.
  • Community and answers. Years of Stack Overflow threads, blog posts, and copied snippets mean most problems already have a solution online.

If your app is React, in the browser, and you're happy with that world, react-query is the safer default. Saying otherwise would be dishonest.

Where alova goes further

alova is a request strategy layer too, but it isn't tied to one framework or one runtime:

  • One API across runtimes. The same useRequest and usePagination calls run on the web, in mobile apps (React Native / Expo), and on the server (Node BFF). You write the request logic once.
  • Server-side hooks. alova/server adds retry and createRateLimiter for your BFF's outbound calls, the layer react-query doesn't touch because it lives in the browser.
  • Framework choice. React, Vue, Svelte, and Solid all get first-class hooks, so a mixed-stack team isn't forced into React.
  • Sits on your existing adapter. alova doesn't send requests itself. It runs on top of a fetch or axios adapter, so axios stays in the picture if you already use it.

Side by side

Concernreact-queryalova
Primary runtimeBrowser (React)Web, mobile, server (BFF)
FrameworkReact-firstReact / Vue / Svelte / Solid
Client cacheExcellent, matureGood, strategy hooks
Server-side retry / rate limitNot its jobalova/server hooks
Cross-platform appsReact Native onlyReact Native, Expo, and more
Sends HTTP itselfNo (fetch/axios under)No (fetch/axios adapter)
Community sizeVery largeSmaller

On the last row: neither library replaces axios. Both sit above a request adapter, so if your team already depends on axios, it keeps doing the sending.

When react-query is the better call

  • Your frontend is React and browser-only, and you want the deepest React caching ecosystem available.
  • You don't run a BFF that needs outbound retry/rate-limit logic.
  • Your team already knows react-query and ships fast with it.

When alova fits better

  • You maintain the same request logic across web, a non-React-Native app, and a Node BFF.

  • Your BFF needs retry with backoff and a client-side rate limit for downstream calls (see the BFF retry post).

  • You're on Vue, Svelte, or Solid, or a mixed stack, and want one strategy layer.

  • alova vs other libraries

  • Server retry strategy