fix: PoolDetailClient shares usePools() cache instead of bypassing it - #180
Merged
prodbycorne merged 7 commits intoAug 17, 2026
Merged
Conversation
getPoolDepositors previously had no query-hook wrapper — it was called from a one-shot useEffect in PoolDetailClient with no refetch policy, so depositor data froze at mount for the page's lifetime (SmartDropLabs#143). staleTime/refetchInterval match usePools()'s policy.
…cache Replaces the direct, uncached sorobanService.getFactoryPools() useEffect with usePools() — the same hook the Farm page's list uses. Visiting /farm then a pool's detail page no longer triggers a second, independent RPC round trip while the cache is fresh, and pool stats now update on usePools()'s 60s refetchInterval instead of being frozen at mount for the page's lifetime (SmartDropLabs#143). pool is now derived via useMemo(() => pools?.find(...)) rather than a one-shot check — recomputes if the pool later disappears from a factory poll (a behavior change from before: previously a pool removed from the factory after initial load stayed displayed until the user navigated away and back).
Replaces the one-shot sorobanService.getPoolDepositors() useEffect with the new usePoolDepositors() query hook, so the Top Depositors table also refreshes on an interval instead of being frozen at mount for the page's lifetime (SmartDropLabs#143).
Fetches through sorobanService.getPoolDepositors with the given poolId/limit, stays disabled (no fetch) when poolId is empty, and defaults limit to 20 when not provided.
Simulates the issue's exact repro: a bare usePools() consumer (the Farm page) populates a shared QueryClient's cache, then PoolDetailClient mounts against the same client for the same pool. getFactoryPools is asserted called exactly once total — the second consumer must not trigger its own independent RPC round trip while the cache is fresh.
Advances past usePools()'s 60s refetchInterval with a changed mocked getFactoryPools response and asserts the displayed dailyRate updates to reflect it — pre-fix, PoolDetailClient had no polling mechanism at all and this figure would stay frozen at its initial value for the lifetime of the page view (SmartDropLabs#143).
…tDropLabs#143) Covers the acceptance criteria's "existing behavior is preserved" requirement directly: loading skeletons show while usePools() is pending, "Pool not found." shows when the resolved pool list doesn't contain the requested poolId, and "Failed to load pool data." shows when the fetch itself fails (advancing through usePools()'s 3-retry exponential backoff via fake timers rather than waiting ~7s of real time).
✅ Deploy Preview for spiffy-melomakarona-eb1e8a ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for smart-drop ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
|
All ci s passed. welldone |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PoolDetailClientfetched pool data and depositors with two hand-rolleduseEffects callingsorobanServicedirectly, entirely bypassing React Query — the samegetFactoryPools()round tripusePools()performs, uncached and with no refetch policy. Visiting/farmthen a pool's detail page triggered a second, fully independent RPC call even though the same data was sitting in theQueryClient's cache moments earlier, and once loaded, the detail page's stats never updated again for the lifetime of the page view.PoolDetailClientnow usesusePools()(the same hook the Farm page's list uses) and derivespoolviauseMemo(() => pools?.find((p) => p.id === poolId) ?? null)— sharing cache,staleTime, andrefetchIntervalwith the Farm page.usePoolDepositors(poolId, limit)hook (staleTime: 30000/refetchInterval: 60000, matchingusePools()) replaces the one-shotgetPoolDepositorsuseEffect.poolviauseMemomeans it now recomputes if the pool later disappears from a factory poll (arguably more correct), whereas before a pool removed from the factory after initial load stayed displayed until the user navigated away and back.Closes #143
Test plan
npx tsc --noEmit— cleannpm run lint— clean (only pre-existing unrelated warnings)npm run build— succeedsnpx vitest run— 231/232 pass; the one failure (soroban-parsers.test.ts) is on a file untouched by this branch, confirmed byte-identical toupstream/main, unrelated to this changeusePoolDepositorsfetches throughsorobanService.getPoolDepositorswith the given poolId/limit, stays disabled when poolId is empty, defaults limit to 20PoolDetailClientmounted against a sharedQueryClientafter a bareusePools()consumer (simulating/farm) does not trigger a secondgetFactoryPools()call — call-count assertion, per the issue's own suggested testPoolDetailClient's displayeddailyRateupdates afterusePools()'s 60srefetchIntervalelapses, where before it would stay frozen at its initial value