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;
image.png
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这样出色的翻译应用程序,所以请务必尝试一下!

广告
将在 10 秒后关闭
bannerAds