我使用 React Query 从外部 API 获取 Json 文件。 下面是获取钩子。
import { QueryClient, QueryKey, useQuery } from "@tanstack/react-query";
let Tmdb: string;
if (typeof process.env.NEXT_PUBLIC_TMDBURL === "string") {
Tmdb = process.env.NEXT_PUBLIC_TMDBURL;
} else {
throw new Error("NEXT_PUBLIC_TMDBURL is not defined");
}
export const useFetchData = () => {
const queryClient = new QueryClient();
const queryKey: QueryKey = ["repoData"];
const { isLoading, error, data } = useQuery({
queryKey,
queryFn: async () => {
const response = await fetch(Tmdb, { method: "GET" });
const data = await response.json();
if (!response.ok) {
throw new Error("Network response was not ok");
}
if (isLoading) {
console.log("ローディング中です");
}
if (error) {
console.log("エラーです");
}
console.log(data);
return data;
},
});
return { data, isLoading, error };
};
下面是使用“useFetchData”钩子的组件。
import { QueryClient } from "@tanstack/react-query";
import { useFetchData } from "../hooks/useFetchData";
function PublishedMovieList() {
const queryClient = new QueryClient();
const { data, isLoading, error } = useFetchData();
// 取得した"data"のタイプを定義する
type FetchData = {
adult: boolean;
backdrop_path: string;
belongs_to_collection: null;
budget: number;
genres: { id: number; name: string }[];
homepage: string;
id: number;
imdb_id: string;
original_language: string;
original_title: string;
overview: string;
popularity: number;
poster_path: string;
production_companies: {
id: number;
logo_path: string;
name: string;
origin_country: string;
}[];
production_countries: { iso_3166_1: string; name: string }[];
release_date: Date;
revenue: number;
runtime: number;
spoken_languages: {
english_name: string;
iso_639_1: string;
name: string;
}[];
status: string;
tagline: string;
title: string;
video: boolean;
vote_average: number;
vote_count: number;
};
// 取得したdataを配列にする
const movieList = (Object.keys(data) as (keyof FetchData)[]).map((keys) => {
return { keys: keys[data] };
});
console.log(movieList);
return (
<div>
<div>
<p className="text-3xl py-5 pl-5">公開中作品</p>
</div>
<div className="flex space-x-10 pl-5">
{movieList.map((item) => (
<section className="w-1/5" key={item.id}>
<img
src={`https://image.tmdb.org/t/p/w185/${item.poster_path}`}
></img>
</section>
))}
</div>
</div>
);
}
export default PublishedMovieList;
下面是“page.tsx”文件。
import PublishedMovieList from "./components/PublishedMovieList";
import Sidebar from "./components/Sidebar";
import {
QueryClient,
QueryClientProvider,
useQuery,
} from "@tanstack/react-query";
const queryClient = new QueryClient();
export default function Home() {
return (
<QueryClientProvider client={queryClient}>
<main className="bg-indigo-950 min-h-screen min-w-full">
<div className="text-5xl py-10 pl-5 border-b border-white">
<h1>今日、何観る?</h1>
</div>
<div className="flex">
<div>
<Sidebar />
</div>
<div>
<PublishedMovieList />
</div>
</div>
</main>
</QueryClientProvider>
);
}
当我启动开发环境时,“只有普通对象和一些内置对象可以从服务器组件传递到客户端组件。不支持类或空原型。”显示。
我使用以下语言。 ・反应版本18 ・Next.js 版本14.1.0 ・TypeScript ver5
我是编码初学者。如果您很难阅读代码,我深表歉意。
我注释掉了“useFetchData”文件,因为我认为在获取过程中存在原因。 但这并没有改善任何事情...
请帮助我。
在
app
路由器中,组件默认是服务器组件(Home
),并且服务器组件只能将 JSON 可序列化属性传递给客户端组件(QueryClientProvider
)。
或者您从
queryClient
传递到 QueryClientProvider
的 Home
是一个包含函数等的复杂对象。这是你的问题。
您可以在
"use client"
顶部添加 Home
使其成为客户端组件,或者将 QueryClientContextProvider
移动到其自己的文件中,如下所示:
// QueryClientContextProvider.tsx
"use client";
import { ReactNode } from "react";
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
const queryClient = new QueryClient();
export default function QueryClientContextProvider({ children }: { children: ReactNode }) {
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
}
import QueryClientContextProvider from "@/components/QueryClientContextProvider";
import PublishedMovieList from "./components/PublishedMovieList";
import Sidebar from "./components/Sidebar";
export default function Home() {
return (
<QueryClientContextProvider>
<main className="bg-indigo-950 min-h-screen min-w-full">
<div className="text-5xl py-10 pl-5 border-b border-white">
<h1>今日、何観る?</h1>
</div>
<div className="flex">
<div>
<Sidebar />
</div>
<div>
<PublishedMovieList />
</div>
</div>
</main>
</QueryClientContextProvider>
);
}