javascriptreactjstypescriptnext.js

Err Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported


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.


Solution

  • 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>
      );
    }