I fetch JSON file from external API using React Query. Below is fetch hook.
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 };
};
And below one is the Component which use "useFetchData" hook.
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;
And below one is "page.tsx" file.
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>
);
}
When I start dev environment,"Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported." displayed.
I use below languages. ・React ver18 ・Next.js ver14.1.0 ・TypeScript ver5
I'm beginner for coding.If you are hard to read code, I apologize.
I commented out the "useFetchData" file because I think there is cause in fetch process. But it doesn't improve anything...
Please help me.
Within the app
router, components are by default server components (Home
), and a server component can only pass a JSON serializable prop to client components (QueryClientProvider
).
Or that queryClient
you are passing to QueryClientProvider
from Home
is a complex object that contains functions and all. This is your problem.
You can add "use client"
at the top of Home
to make it a client component or, move the QueryClientContextProvider
in its own file, like so:
// 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>
);
}