我正在开发 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 客户端不使用缓存数据吗?
如果两个查询同时发生,网络请求将被重复数据删除。
由于您单独使用 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" },
。