From d2ab2b9eda87b210d541f45b7e2a536d5da150b2 Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Wed, 10 Jun 2026 12:37:24 -0700 Subject: [PATCH] fix(feed): prevent Latest feed from blanking on background refetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the same staleTime + enabled guard fix that was landed in useForYouFeed (commit 3d65667e35) to the "Latest" chronological feed hook, which was left behind. Bug 1 — missing staleTime: useFeed had no staleTime, so the react-query default of 0 caused the query to refetch immediately after the first paint on every mount/focus. If that refetch settled empty (transient backend result, or a different validator node in the fleet), react-query replaced the populated feed with `[]`. The lineup reads an empty list as "no content" and renders the empty state, causing the feed to flash and then blank. Fix: staleTime: 5 * 60 * 1000 (5 min, overridable via options). Infinity is used for the For You feed because those results are personalised and session-stable; 5 min is used here because the Latest feed is chronological and users reasonably expect fresh content when they return after a while. Bug 2 — enabled logic override / undefined account: The hook spread ...options after the enabled field, so any options.enabled: false passed by a caller was silently discarded. Worse, the check used !== null (strict), so while the account is still resolving and currentUserId is undefined the query fired, ran the !currentUserId guard inside queryFn, and returned [], caching that empty result under the [feed, undefined] key. A later render could briefly read that key and flash the empty state. Fix: move enabled after ...options with the same guard used in useForYouFeed (options?.enabled !== false && currentUserId != null). Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../common/src/api/tan-query/lineups/useFeed.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/common/src/api/tan-query/lineups/useFeed.ts b/packages/common/src/api/tan-query/lineups/useFeed.ts index a2f95257d23..bd764aad852 100644 --- a/packages/common/src/api/tan-query/lineups/useFeed.ts +++ b/packages/common/src/api/tan-query/lineups/useFeed.ts @@ -107,8 +107,23 @@ export const useFeed = ( ) }, select: (data) => data?.pages.flat(), + // Keep the loaded feed stable for 5 minutes. Without a staleTime the + // react-query default of 0 causes the query to refetch on the next + // mount/focus right after the first paint. If that refetch settles + // empty (transient backend result, or a different validator node in + // the fleet returning nothing), react-query replaces the populated + // feed with `[]` — the same blank-feed bug fixed in useForYouFeed + // via staleTime: Infinity. 5 minutes is used here instead because + // the "Latest" feed is chronological and users expect fresh content + // when they return after a while; Infinity would suppress that. + // Callers can override via options.staleTime if needed. + staleTime: 5 * 60 * 1000, ...options, - enabled: currentUserId !== null + // Require a fully-resolved id (`!= null` excludes `undefined`). While + // the account is still loading `currentUserId` is `undefined`; running + // the query then would cache `[]` under the `[feed, undefined]` key — + // an entry a later render could briefly surface as "no content". + enabled: options?.enabled !== false && currentUserId != null }) const data = query.data ?? []