我有一个使用 Next.js 的单页应用程序。我正在建立一个类似于 https://nflscorigami.com/ 但针对 NBA 的网站。在我的 postgresql 数据库中,我有一个包含大约 70k 行的表,其中包含每场 NBA 比赛。
在我的 trpc API 中我有
getGames: publicProcedure.query(async ({ ctx }) => {
const allGames = await ctx.db.query.nbaGames.findMany();
return {
games: allGames,
};
}),
在我的主要图表组件中,我使用
获取此数据const { data: gamesData, isLoading: loadingGamesData } = api.game.getGames.useQuery();
我在热图中呈现数据,热图加载大约需要 10 秒。数据集只会在当天的比赛结束后更新一次。如何将这些数据缓存 1 天,以减少每次打开和刷新页面时的加载时间和数据库请求?
我尝试更改 React Query 的 staleTime 和 gcTime 但这没有帮助。我还尝试了 trpc 文档在https://trpc.io/docs/server/caching中建议的内容。
export function TRPCReactProvider(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();
queryClient.setDefaultOptions({
queries: {
staleTime: 12 * (60 * 60 * 1000), // 12 hours
gcTime: 12 * (60 * 60 * 1000), // 12 hours
},
});
const [trpcClient] = useState(() =>
api.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
transformer: SuperJSON,
url: getBaseUrl() + "/api/trpc",
headers: () => {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
headers.set(
"cache-control",
`s-maxage=${ONE_DAY_IN_SECONDS}, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
);
return headers;
},
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<api.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</api.Provider>
</QueryClientProvider>
);
}
您的方法的主要问题是您没有正确利用 Next.js 的功能,因为:
A) 通过从客户端组件获取,您需要一个中间人(您的 API),这会增加延迟。此外,客户端将必须接收所有 70k 记录,并且我假设计算热图的值,这至少可以说并不理想。
B) 如果用户浏览应用程序并返回到您的热图,客户端上的缓存可能会有所帮助,但考虑到您只有一个页面,我认为这没有太多用处。
最有前途的方法是使用 Next.js 的 ISR 功能(增量静态再生)来获取数据,在服务器上对热图进行计算,然后使用以下方法将此数据缓存所需的持续时间:
export const revalidate
变量。鉴于您使用 tRPC,您需要实例化一个可以在服务器上运行的 tRPC 客户端,并使用它来获取 服务器组件中的数据,同时利用 ISR。
我头顶的一个例子可能看起来像这样(还没有测试过):
export const trpcProxyClient = createTRPCProxyClient<AppRouter>({
transformer: superjson,
links: [
httpBatchLink({
url: getBaseUrl() + "/api/trpc",
}),
],
});
export const tRPCServerClient = createServerSideHelpers({
client: trpcProxyClient,
});
(假设您正在使用App Router)
export const revalidate = 60
// calculate expensive stuff here
const expensiveCalculationForHeatmap = (games) => {}
export default async function Page() {
const { data } = await tRPCServerClient.games.getAll.fetch()
const transformedData = expensiveCalculationForHeatmap(data)
return (
<HeatmapClientComponent data={transformedData}/>
)
}