Apollo 客户端缓存问题与 fetchPolicy:Next.js 服务器组件中的“无缓存”

问题描述 投票:0回答:1

我正在开发 Next.js 服务器组件来从 GraphQL 服务器获取事件,但我遇到了一个问题,尽管设置了 fetchPolicy: 'no-cache',但似乎仍在使用缓存。这是我的设置:

// lib/apollo-client.ts

import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
  uri: process.env.NEXT_PUBLIC_GRAPHQL_URI || 'http://localhost:3000/api/graphql', // Fallback to localhost
  cache: new InMemoryCache(),
  connectToDevTools: true,
  defaultOptions: {
    query: {
      fetchPolicy: 'no-cache',  // Disable caching for queries
      errorPolicy: 'all',
    },
  }
})

export default client;

// app/events/page.tsx

import client from "@/lib/apollo-client";
import { EventProps } from "@/types";
import { getAllRecords } from "@/utils/airtable/client";
import { gql } from "@apollo/client";
import { Box, Grid, Card, CardContent, Typography, CardActions, Button, Divider } from "@mui/material";
import EventsDataGrid from "../components/EventsDataGrid";

const EVENT_QUERY = gql`
    query EventQuery {
        events {
            id
            name
        }
    }
`;

async function fetchData() {
    const events: EventProps[] = [];
    const newEvents: EventProps[] = [];

    // Fetch events from GraphQL
    try {
        client.cache.reset();
        const { data } = await client.query({
            query: EVENT_QUERY,
            fetchPolicy: 'no-cache', // Ensure cache is not used
        });

        events.push(...data.events);
    } catch (error) {
        console.error('Error fetching events from GraphQL:', error);
    }

    // Fetch new events from Airtable
    try {
        const records = await getAllRecords<EventProps>('events', `OR({id} = '', {id} = BLANK())`);
        records.forEach((newEvent) => {
            const { name } = newEvent.fields;
            newEvents.push({
                name,
                airtableId: newEvent.id
            });
        });
    } catch (error) {
        console.error('Error fetching events from Airtable:', error);
    }

    return { events, newEvents };
}

export default async function EventsPage() {
    const { events, newEvents } = await fetchData();

    return (
        <Box sx={{ flexGrow: 1 }}>
            <Grid container spacing={3}>
                {events.map((event) => (
                    <Grid item lg={12} md={12} xs={12} key={event.id}>
                        <Card sx={{ minWidth: 275 }}>
                            <CardContent>
                                <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
                                    {event.name}
                                </Typography>
                            </CardContent>
                            <CardActions>
                                <Button href={`event/${event.id}`} size="small">View</Button>
                            </CardActions>
                        </Card>
                    </Grid>
                ))}
                
                {/* New events */}
                <Grid item lg={12} md={12} xs={12}>
                    <Typography variant="h6">
                        New Events
                    </Typography>
                    <Divider />
                    <EventsDataGrid events={newEvents} />
                </Grid>
            </Grid>
        </Box>
    );
}

问题: 尽管设置了 fetchPolicy: 'no-cache',GraphQL 查询仍然返回缓存的数据。我什至尝试在查询之前调用 client.cache.reset() ,但它没有解决问题。

我错过了什么或做错了什么?我需要采取其他步骤来确保 Apollo 客户端不使用缓存数据吗?

next.js caching graphql apollo-client
1个回答
0
投票

如果两个查询同时发生,网络请求将被重复数据删除。

由于您单独使用 Apollo Client,而不是

"@apollo/experimental-nextjs-app-support"
包(您真的应该这样做),如果没有新的 React 功能或面向您的框架的包,就无法支持像 Next.js 这样的流式 SSR。正在使用!),您正在创建
client
的一个全局实例。

该实例是在所有传入网络请求之间共享,这意味着在所有活动用户之间共享 - 您很容易陷入这样的情况:同一查询同时发生两次,被删除,看起来好像正在使用缓存。

虽然您可以禁用重复数据删除,但我强烈建议您使用

"@apollo/experimental-nextjs-app-support"
包,因为这可以确保每个传入请求都有一个单独的
ApolloClient
实例,并且数据不能在用户之间混合。您甚至不需要禁用缓存。

import { HttpLink } from "@apollo/client";
import {
  registerApolloClient,
  ApolloClient,
  InMemoryCache,
} from "@apollo/experimental-nextjs-app-support";

export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({
      // this needs to be an absolute url, as relative urls cannot be used in SSR
      uri: "http://example.com/api/graphql",
      // you can disable Next.js fetch result caching here if you want to
      // (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
      fetchOptions: { cache: "no-store" },
    }),
  });
});

最重要的是,Next.js 很可能会缓存传出的网络请求,因此如果您想阻止 Next.js 这样做,则需要设置

fetchOptions: { cache: "no-store" },

© www.soinside.com 2019 - 2024. All rights reserved.