skip to content

A cached list refetches on mount, on window focus and on reconnect, and users see constant loading. How would you decide which triggers to keep?

level: seniorimportance: should knowfreq 55%

answer

  1. pixels and requests are different complaints
  2. placeholder over populated data: a keying bug
  3. the staleness window is the volume control
  4. focus is a multiplier per entry
  5. reconnect earns its keep

basics

~20 s

Separate two symptoms: too many requests, and content replaced by a placeholder. Loading over an existing entry points at a missing or unstable key, not a trigger. Then keep each trigger only where data changes unobserved and refetching is cheap.

solid answer

~40 s

Constant loading and constant refetching are different bugs, so split them before touching triggers. A background refetch over a populated entry should keep content on screen; if the user sees a placeholder, either the entry is missing — usually an unstably built key, or retention dropped it — or the screen shows a placeholder whenever anything is in flight. Fix that first and the triggers may become acceptable. Then tune volume by raising the staleness window, since triggers only cause work on entries considered untrusted. Keep reconnect almost always, because time passed unobserved while offline. Keep mount for screens the user enters deliberately. Treat focus refetching as per-surface, gated on the entry being genuinely old. Treat interval polling as an explicit product decision, only for data that changes without the user acting.

go deeper

for a junior

Recall the triggers by name and what each assumes: entering a screen, returning to the tab, regaining a connection, a timer, and an explicit invalidation after something changed.

for a middle

Explain that a trigger only asks the cache to consider refetching, so the staleness window governs how many actually become requests, and that one event must produce one request per key rather than one per subscriber.

for a senior

Separate the pixel complaint from the request complaint before tuning, suspect unstable keys behind loop-like refetching, and justify each trigger per surface with a measured request count.

for a principal

Set the policy: which data classes get which window, where focus and interval refetching are permitted, and what request-per-session budget the app is held to as screens are added.

## Two complaints wearing one costume `constant loading` is a statement about pixels; `constant refetching` is a statement about requests. They have different causes and different fixes, and tuning triggers before separating them usually makes the app staler without making it calmer. A background refetch over an entry that already holds a value must not blank the screen. If it does, the cause is one of three, none of which is the trigger: 1. **The entry is missing, not stale.** The read is a cold miss, so a placeholder is correct. The interesting question becomes why the entry is missing. 2. **The key is unstable.** If a key is rebuilt from a freshly constructed object, an unpinned timestamp, or a value that changes identity each render, every read asks a new question. The cache reports a miss, the app looks like it is refetching in a loop, and memory fills with one-shot entries. This is the single most common misdiagnosis in this area. 3. **The reader renders a placeholder for any in-flight request.** The screen is conflating the first load with a revalidation. Rendering data plus a subdued indicator when a value exists removes the symptom entirely. ## Then reduce volume at the source Triggers do not fetch by themselves; they ask the cache to consider refetching, and an entry inside its staleness window is normally left alone. So the staleness window is the master volume control: with a window of zero, every trigger is a request, and the app behaves as if uncached. Raising it to a value the product can accept removes most of the traffic without disabling anything. Deduplication matters here too: several subscribers reacting to the same event must produce one request per key, not one per component. ## Judging each trigger | trigger | what it assumes | keep it when | the cost | |---|---|---|---| | on mount / on becoming subscribed | time passed while nobody was watching | the screen is entered deliberately and the entry is past its window | one request per navigation to that screen | | on window or tab focus | the user was away, and others kept working | the surface shows shared or fast-moving data | an entry-count-times-tab-switch multiplier on a busy screen | | on reconnect | changes happened while the client had no link | almost always | a burst of requests exactly when the link is weakest | | on an interval | the data changes with no user action | dashboards, queues, status boards | steady traffic for as long as the screen is open, including idle | | on explicit invalidation | something known made the entry wrong | always, this is the precise one | none beyond the refetch itself | The distinctions to keep in mind: - **Focus is a multiplier, not a request.** A screen holding twenty cached entries refetches twenty times per return to the tab unless it is gated by the staleness window or narrowed to the entries that matter. Gate it, batch it, or restrict it to the surfaces where a user genuinely comes back expecting fresher numbers. - **Reconnect is the cheapest correctness win.** Being offline is exactly the case where the client knows it missed changes. The care needed is at the burst: stagger or cap the requests so a flaky link does not produce a storm, and expect some to fail again. - **Interval polling deserves a named owner.** It is the only trigger that spends requests while the user does nothing, and it is often used as a substitute for an explicit invalidation or a push channel. ## How to decide with evidence 1. Count requests per session per key family, and split them by trigger. A single dominant family is usually the whole problem. 2. For that family, ask what the worst consequence of a value one window old actually is. Money, stock and permissions justify short windows; labels, taxonomies and profile names do not. 3. Set the window from that answer, then keep the triggers that cover the ways time passes unobserved: reconnect, and mount for entered screens. 4. Add focus refetching per surface rather than app-wide, and interval polling only where the product needs it. 5. Re-measure. The target is a request count proportional to the user's actions plus the ways they were away, not to the number of components on screen.

  • Why can an unstable cache key look exactly like an over-eager refetch trigger?
    Because both produce a request on every render or navigation. The difference is what the cache reports: an unstable key never matches an existing entry, so every read is a miss with a real loading state and a new entry left behind. Log hit and miss counts per key family and the two become easy to tell apart.
  • Why is refetching on reconnect easier to justify than refetching on focus?
    Being offline is direct evidence that the client could not have received changes, and it happens rarely. Focus happens constantly, and on a screen with many cached entries it multiplies into many requests for data that may be seconds old. Reconnect buys correctness cheaply; focus has to be earned per surface.
  • When is interval polling the wrong answer for a screen that must stay current?
    When changes are event-shaped rather than continuous. Polling then spends requests during quiet periods and still lags the change by up to one interval. An explicit invalidation at the moment something changes, or a push channel feeding the cache, gives lower latency for far fewer requests.

saying these in an interview costs you the question

  • Disables all refetch triggers to stop visible loading
  • Blames triggers for a placeholder over populated data
  • Enables focus refetching app-wide without a staleness window
  • Uses interval polling as the default freshness mechanism
  • Ignores that one event must yield one request per key
  • Never measures requests per session before tuning