Skip to content

Instantly share code, notes, and snippets.

@mmikhan
Created April 27, 2025 11:05
Show Gist options
  • Save mmikhan/f9f42c9d4d53b635564d989fab96ef29 to your computer and use it in GitHub Desktop.
Save mmikhan/f9f42c9d4d53b635564d989fab96ef29 to your computer and use it in GitHub Desktop.
Manual dehydration on a T3 app through the `useAuthQuery` hook
import { auth } from "@/server/auth";
import { createQueryClient } from "@/trpc/query-client";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query"; // Import dehydrate and HydrationBoundary
import { headers } from "next/headers";
import Link from "next/link";
import { cache } from "react";
import StateView from "./state";
// Cache the QueryClient per request in RSC
const getQueryClient = cache(() => createQueryClient());
export default async function DashboardPage() {
const queryClient = getQueryClient();
const reqHeaders = await headers();
await queryClient.prefetchQuery({
queryKey: ["polarCustomerState"],
queryFn: () => auth.api.polarCustomerState({ headers: reqHeaders }),
});
// Manually dehydrate the state *after* prefetching
const dehydratedState = dehydrate(queryClient);
// Optional: Keep the log to verify server state if needed
// console.log("Server Prefetch Result:", JSON.stringify(queryClient.getQueryData(["polarCustomerState"]), null, 2));
return (
// Use HydrationBoundary and pass the dehydrated state explicitly
<HydrationBoundary state={dehydratedState}>
<div className="relative flex min-h-[100dvh] flex-col items-center justify-center gap-4 bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
<h1 className="font-bold text-4xl">Dashboard</h1>
{/* Link to the Polar Customer Portal */}
<Link
href="/api/auth/portal" // Directly targets the API endpoint
className="text-blue-400 underline hover:text-blue-300"
target="_blank" // Optional: open in a new tab
rel="noopener noreferrer" // Security measure for target="_blank"
>
Manage Subscription
</Link>
{/* Render the client component that will display the state */}
<StateView />
<Link
href="/"
className="absolute top-4 left-4 text-gray-300 text-sm hover:text-gray-100"
>
Back to Home
</Link>
</div>
</HydrationBoundary>
);
}
"use client";
import { useAuthQuery } from "@/lib/auth-hooks"; // Import the hook
export default function StateView() {
const {
data: state,
isLoading,
error,
} = useAuthQuery({
queryKey: ["polarCustomerState"],
// Add queryFn back for background updates and stale refetches
queryFn: async () => {
const response = await fetch("/api/auth/state");
if (!response.ok) {
// Try to parse error details if available
let errorBody = "Failed to fetch state client-side";
try {
const errJson = await response.json();
errorBody = errJson.message || errorBody;
} catch (e) {
// Ignore if response is not JSON
}
throw new Error(errorBody);
}
return await response.json();
},
});
// Display loading state (should be brief or skipped due to hydration)
if (isLoading) {
return <p className="text-gray-400">Loading customer state...</p>;
}
// Display error state
if (error) {
return <p className="text-red-400">Error loading state: {error.message}</p>;
}
// Display the fetched data
return (
<pre className="mt-4 max-w-lg overflow-auto rounded bg-gray-800 p-4 text-left text-sm">
{state ? JSON.stringify(state, null, 2) : "No state data available."}
</pre>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment