feat(web): wire tRPC React Query client and retire the vanilla stub - #381
Conversation
|
@ntttttbl123-blip 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! 🚀 |
✅ Deploy Preview for stellar-signet ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
@ntttttbl123-blip is attempting to deploy a commit to the blockchainmaxis-8449's projects Team on Vercel. A member of the Team first needs to authorize it. |
blockchain-maxis
left a comment
There was a problem hiding this comment.
This is the migration the TODO in lib/trpc.ts was asking for, and the details are right. Creating the QueryClient and tRPC client in useState initialisers instead of at module scope — with the comment explaining that a module-level client would be shared across server requests and leak one user's cache into another's render — is the part people usually get wrong. The seeded ref so a post-save refetch can't clobber in-flight edits, and invalidate() on success so other readers see the edit, are both correct.
Two problems, both from the branch being based on 8216232.
1. Deleting lib/trpc-client.ts breaks a second caller that landed since. #333 ("feat(web): let a wallet be unlinked from the dashboard") added apps/web/app/(dashboard)/app/wallets/unlink-wallet-button.tsx, which does:
import { trpc } from '@/lib/trpc-client';Your PR removes that module and migrates only profile-editor.tsx, so after a rebase the wallets page won't resolve its import. unlink-wallet-button.tsx needs the same treatment — trpc.account.unlinkWallet.useMutation() in place of the vanilla .mutate() call — and it will need to be inside TRPCProvider, which your (dashboard)/layout.tsx change already covers.
2. lib/trpc.ts conflicts.
CONFLICT (content): Merge conflict in apps/web/lib/trpc.ts
CONFLICT (content): Merge conflict in pnpm-lock.yaml
#316 landed an hour ago and rewrote getBaseUrl() in that file to go through appUrl() from lib/public-env.ts, so the server-side branch returns the guarded origin rather than a raw process.env read. Your version replaces the whole module with createTRPCReact<AppRouter>(), which has no transport and therefore no base URL at all.
That's fine if nothing calls tRPC from the server — and as far as I can tell nothing does; the two importers are both client components, and the public read surfaces call the profile helpers directly, as your doc comment says. Worth stating that explicitly in the PR description though, because it means #316's appUrl() wiring in trpc.ts becomes dead code that this PR is deliberately dropping rather than accidentally reverting. If it turns out something does need a server-side caller later, it should be a separate server-only module, not this one.
The lockfile conflict is just main having moved; regenerate it after the rebase.
Rebase onto main, migrate unlink-wallet-button.tsx, and I'll take it.
Resolves the conflicts between the React Query tRPC migration and main: - apps/web/lib/trpc.ts: keep the createTRPCReact client. Main had rewritten the vanilla client's getBaseUrl to use appUrl(); that whole code path is retired here, so the appUrl import goes with it. The transport lives in trpc-provider.tsx against a relative /api/trpc. - pnpm-lock.yaml: regenerated from main's lockfile rather than merged by hand, so main's @trezor/* bump is preserved while @trpc/react-query and @tanstack/react-query are added. - apps/web/app/(dashboard)/app/wallets/unlink-wallet-button.tsx: main added this after the PR branched, and it imported the deleted lib/trpc-client. Migrated to trpc.account.unlinkWallet.useMutation() with the same two-step confirm, pending label and error handling, and it now invalidates account.me alongside router.refresh().
6fc0c52
into
blockchain-maxis:main
Closes #225.
What
Replaces the vanilla tRPC stub with the real
@trpc/react-queryintegration so client components get caching, request deduplication, and invalidation.lib/trpc.ts— now exports acreateTRPCReact<AppRouter>()client (typeduseQuery/useMutationhooks); theTODO(signet)and the old vanilla client are retired.lib/trpc-provider.tsx(new) — a'use client'TRPCProvidermountingQueryClientProvider+ the tRPC provider. TheQueryClientand tRPC client are created viauseStateinitialisers (per-mount, not module scope) so one request's cache can't leak into another's server render.app/(dashboard)/layout.tsx— wraps the authenticated dashboard children in<TRPCProvider>(only when signed in).app/(dashboard)/app/profile/profile-editor.tsx— migrated from the hand-rolleduseEffect/.query()/.mutate()toaccount.me.useQuery()+account.update.useMutation(). A successful save now invalidatesaccount.me, so the profile refetches instead of holding stale values. The loading / error / no-profile / ready states and the "configured database" and "claim a handle first" messages are preserved.lib/trpc-client.ts— deleted; the dashboard's only consumer now uses the React Query client.package.json— adds@trpc/react-queryand@tanstack/react-query; lockfile updated.Public read surfaces stay server-rendered and call the profile helpers directly — the client is only for the authenticated dashboard.
Verification
pnpm --filter @signet/web typecheck— cleanpnpm --filter @signet/web lint— cleanpnpm --filter @signet/web test— 207 passingpnpm --filter @signet/web build— succeeds