Next.js 13和TanStack Query(React Query)的注意事项
首先
由于使用Next.js 13和TanStack Query(React Query)遇到了一些困难,我将它们作为备忘录发布出来。
目前(2023/08),关于这方面的日文文章还比较少,所以我进行了信息搜集并整理了起来。
如果对你有帮助的话,我也会非常高兴!
为什么迷上了它?
具体的说,我在使用useQuery时遇到了困难。
理由
只能在客户端组件中使用useQuery,但是默认情况下Next.js 13是服务器组件。
因此,需要单独进行设置才能使用useQuery。
通常情况下,可以按照以下方式生成QueryClient实例,并将生成的实例设置到QueryClientProvider中,然后将父组件包装在QueryClientProvider里即可使用useQuery。但是在Next.js 13中,这种方法无法正常工作。
import './globals.css'
import type { Metadata } from 'next'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
const client = new QueryClient();
const RootLayout: React.FC<{ children: React.ReactNode }> = ({
children
}) => {
return (
<html lang="en">
<body>
<QueryClientProvider client={client}>
{children}
</QueryClientProvider>
</body>
</html>
)
}
export default RootLayout;
解决方案 cè àn)
请参阅TanStack Query文档中的内容。
创建Providers,并将父组件包裹在Providers中。
安装所需的库是为了创建提供程序。
移动到项目的根目录并执行下列操作。
npm install @tanstack/react-query-next-experimental
提供者的创建
使用ReactQueryStreamedHydration包装children,并使用设置了QueryClient的QueryClientProvider来包装ReactQueryStreamedHydration。
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import * as React from 'react'
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'
export function Providers(props: { children: React.ReactNode }) {
const [queryClient] = React.useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<ReactQueryStreamedHydration>
{props.children}
</ReactQueryStreamedHydration>
</QueryClientProvider>
)
}
在父组件中设置提供者
如果在整个项目中使用useQuery,您需要在根目录(在Next.js 13中为layout.tsx)中设置Providers。只需导入先前创建的Providers并将其包装在children周围即可。
import './globals.css'
import type { Metadata } from 'next'
import Providers from '@/providers'
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
const RootLayout: React.FC<{ children: React.ReactNode }> = ({
children
}) => {
return (
<html lang="en">
<body>
<Providers>
{children}
</Providers>
</body>
</html>
)
}
export default RootLayout;
使用useQuery进行操作验证
终于可以使用 useQuery 了!在使用 useQuery 时,需要将要使用的组件视为客户端组件,不要忘记在文件开头加上”use client;”!
"use client";
import { useQuery } from "@tanstack/react-query";
import PostResponseType from "@/types/postResponseType";
import axios from "../lib/axios";
import Loading from "@/components/Loading";
export const Page: React.FC = () => {
const getData = async (): Promise<PostResponseType[]> => {
const res = await axios.get("/posts");
return res.data ?? [];
}
const { data, isLoading, isError } = useQuery<PostResponseType[]>({
queryKey: ["posts"],
queryFn: getData
});
return (
<div className="p-4">
<div className="pb-8 text-5xl text-center">posts</div>
<div className="pb-8 w-3/5 m-auto">
{isLoading ? (
<Loading
text="データ取得中です。しばらくお待ちください。"
/>
) : isError ? (
<p>Error!</p>
) : (
data?.map((post, index) => (
<ul key={index} className="pb-8 text-left">
<li>
<strong>userId: </strong>
<span>{post.userId}</span>
</li>
<li>
<strong>id: </strong>
<span>{post.id}</span>
</li>
<li>
<strong>title: </strong>
<span>{post.title}</span>
</li>
<li>
<strong>body: </strong>
<span>{post.body}</span>
</li>
</ul>
))
)}
</div>
</div>
)
}
export default Page;
Unhandled Runtime Error
Error: Attempted to call useQuery() from the server but useQuery is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.
结尾处
有时即使没有日语信息,也可以通过用英语进行搜索来解决问题!即使不懂英语,也有像DeepL这样出色的翻译应用程序,所以请务必尝试一下!