perf(web): memoize RegistryClient in useProfile to stop per-call client churn (#660) - #733
Open
Oyinkans0la12 wants to merge 1 commit into
Open
Conversation
useProfile re-constructed a new RegistryClient on every queryFn/mutationFn call, including each interval refetch. Construct the client once per mount with useMemo (mirroring usePool) and reuse it across the profile, isVerified, and register call sites, guarding against a null client when the contract ID is not configured. Add a test that spies on the RegistryClient constructor to verify exactly one instance is created per mount and reused across re-renders, refetches, and mutations. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@Oyinkans0la12 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
@Oyinkans0la12 is attempting to deploy a commit to the K1NGD4VID Team on Vercel. A member of the Team first needs to authorize it. |
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
Closes #660
Memoizes a single
RegistryClientinstance inuseProfileso the SDK client is constructed once per hook mount and reused across all three call sites (profile fetch, verified-state fetch, and register mutation), instead of being re-constructed on every queryFn/mutationFn invocation.Problem
apps/web/hooks/useProfile.tsconstructednew RegistryClient(registryContractID)independently in three separate places:profileQuery'squeryFn(~line 73)isVerifiedQuery'squeryFn(~line 93)registerMutation'smutationFn(~line 114)Because those factories run on every query/mutation execution, each refetch — including interval/polling-based refetches — and each register call spun up a brand-new SDK client object (which internally builds a Stellar
Contractinstance and validates the contract ID). This is avoidable object churn on a hook that refetches regularly.Root Cause
The client object is stateless for the purpose of these calls — the contract ID is a module-level constant (
registryContractID), so nothing about the client depends on the wallet address, query args, or render state. There is no reason to rebuild it per call.Solution
Following the existing pattern already established in
usePool.ts(const poolClient = useMemo(() => new PoolClient(poolContractID), [])):registryClientcreated insideuseMemo(..., [])at the top ofuseProfile, so it is constructed exactly once per mount.new RegistryClient(registryContractID)call sites with the memoizedregistryClient.usePool's defensive handling: theuseMemowraps construction in atry/catchand falls back tonull, and each call site guards withthrow new Error("Registry client not available"). This keeps the graceful error behavior for misconfigured environments (emptyNEXT_PUBLIC_REGISTRY_CONTRACT_ID) intact — previously the constructor error surfaced when a query/mutation ran, and it still surfaces at the point of use instead of crashing the render (the hook is used byNavbar, so a render-time throw would break every page).Files changed
apps/web/hooks/useProfile.tsuseMemo-memoizedregistryClient; reuse it in all three call sites with null guardsapps/web/hooks/useProfile.test.tsRegistryClientconstructor is called exactly once per mountAcceptance Criteria Verification
The issue's acceptance criteria:
Covered by the new test
"constructs exactly one RegistryClient instance per mount", which:refetchProfile()(both queries refetched),RegistryClientwas constructed exactly once and with the expected contract ID,Local Verification (all CI pre-checks pass)
Ran the same checks CI runs in
.github/workflows/ci.ymlon this branch:pnpm typecheck— TypeScript passes across SDK + web workspaces (after@trusttrove/sdk build, matching CI's build-first order)pnpm test— SDK suite + all 425 web tests pass (11/11 inuseProfile.test.ts)pnpm --filter web lint— clean (only pre-existing warnings, no errors)pnpm build(with the CI contract-ID env vars) — SDK + Next.js production build succeednpx prettier --check .— all files formattedgo build ./...,go vet ./...,go test ./...Testing Notes
All existing component/page tests (
Navbar,InvoiceCard,marketplace,dashboard,profile) mock@/hooks/useProfileentirely, so no other tests are affected by this change. The SDK and contract layers are untouched.Checklist
usePool.ts)