Я создал следующее приложение js 14.2.3, и у меня есть конечная точка API Graphql (** которую я заменил на localhost для stackOverflow), и я использую "@apollo/client":"^3.10.3", "graphql":"^16.8.1" для получения данных. Я создал путь к странице продукта «страницы/продукты».
import { useQuery, gql } from "@apollo/client";
import { initializeApollo } from "../lib/apollo-client";
const PRODUCTS_QUERY = gql`
query Products {
products(first: 10, channel: "default-channel") {
edges {
node {
id
name
}
}
}
}
`;
function Products() {
const apolloClient = initializeApollo();
const { data, loading, error } = useQuery(PRODUCTS_QUERY, {
client: apolloClient,
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>Products</h1>
<ul>
{data &&
data.products.edges.map(({ node }) => (
<li key = {node.id}>{node.name}</li>
))}
</ul>
</div>
);
}
export default Products;
Я создал файл apollo-client,js.
import { useMemo } from "react";
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
let apolloClient;
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === "undefined",
link: new HttpLink({
uri: "http://localhost:8000/graphql/",
}),
cache: new InMemoryCache(),
});
}
export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient();
// If your page has Next.js data fetching methods that use Apollo Client, the initial
state;
// gets hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState);
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === "undefined") return _apolloClient;
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
}
поэтому, когда я маршрутизирую http://localhost:3000/pages/products
получаю ошибку -



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, это потому, что компонент <Products /> в настоящее время отображается как серверный компонент. А контексты недоступны для серверных компонентов.
Есть два способа это исправить:
заключается в том, чтобы сделать этот компонент клиентом, добавив "use client" поверх pages/products.
Перепишите компонент, чтобы использовать клиент Apollo напрямую, не полагаясь на перехватчик useQuery. Вотхороший арт, объясняющий, как это сделать.
Пример сырости:
import { gql } from "@apollo/client";
import { initializeApollo } from "../lib/apollo-client";
const PRODUCTS_QUERY = gql`
query Products {
products(first: 10, channel: "default-channel") {
edges {
node {
id
name
}
}
}
}
`;
async function Products() {
const apolloClient = initializeApollo();
const { data } = await apolloClient.query({
query: PRODUCTS_QUERY,
context: {},
});
return (
<div>
<h1>Products</h1>
<ul>
{data?.products?.edges?.map(({ node }) => (
<li key = {node.id}>{node.name}</li>
))}
</ul>
</div>
);
}
export default Products;
Недавно я тоже столкнулся с этой ошибкой. Я попробовал первое исправление , данное Ярославом Соболевым, но хотя я использовал «использовать клиент» вверху страницы, это было бесполезно, затем я узнал настоящую причину этой ошибки, которая заключалась в том, что провайдер @apollo/client должен находиться в клиентской среде.
Вот как настроить поставщика в клиентской среде.
Сначала создайте файл Provider.tsx в корневой папке или папке GraphQL.
провайдер.tsx
"use client";
import React, { ReactNode } from "react";
import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
export const Provider = ({ children }: { children: ReactNode }) => {
const client = new ApolloClient({
uri: "http://localhost:5050/graphql",
cache: new InMemoryCache(),
});
return <ApolloProvider client = {client}>{children}</ApolloProvider>;
};
А теперь поместим этого провайдера в файл Layout.tsx.
макет.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { Provider } from "@/graphql/provider";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang = "en">
<body className = {inter.className}>
<Provider>{children}</Provider>
</body>
</html>
);
}