Next.js是否缓存带搜索参数的路由?如何分别缓存不同参数路由?
问题描述
我有一个名为/search的路由,它是客户端组件,会根据搜索参数展示内容。比如访问/search?q=one时,会发送带查询参数的请求并展示关键词'one'的相关结果;访问/search?q=two也正常,但点击浏览器返回按钮回到/search?q=one时,URL变了但结果还是'two'的内容。
相关代码
app/search/page.tsx
import WaterFall from "@/components/layout/WaterFall" interface Props { searchParams: { q: string } } export default function Page({ searchParams }: Props) { const keyword = searchParams["q"]?.trim() return ( <main> <WaterFall param={{ keyword }} /> </main> ) }
Waterfall.tsx(仅贴出数据获取和展示相关代码)
'use client' import { useEffect, useState } from "react" import { useQuery } from "@apollo/client" import { FETCH_CARDS } from "@/lib/apolloRequest" interface Props { param: Object } export default function Waterfall({ param }: Props) { const [cards, setCards] = useState([]) const { loading: initialLoading, data: initialData } = useQuery(FETCH_CARDS, { variables: { ...param, }, }) useEffect(() => { if (initialLoading || !initialData) return setCards(initialData.cards) }, [initialLoading]) return ( <div> {cards.map((card) => ( <Card key={card._id} card={card} /> ))} </div> ) }
疑问
- Next.js是否会缓存带搜索参数的路由?是否忽略了参数?
- 如何分别缓存
/search?q=one和/search?q=two的内容?
原因与解决方案
问题根源
你的问题不是Next.js路由缓存导致的,而是Apollo Client缓存策略和组件状态更新逻辑的问题:
useQuery默认会缓存查询结果,若未配置正确的缓存标识,不同搜索参数可能复用旧缓存;useEffect的依赖项只有initialLoading,当搜索关键词变化时,新的查询数据返回后无法触发状态更新,导致页面展示旧内容;- Next.js的App Router中,客户端组件会随路由参数变化重新渲染,但你的
Waterfall组件没正确响应参数变化。
解决步骤
修正Apollo useQuery缓存配置
给useQuery添加notifyOnNetworkStatusChange: true,并手动指定包含搜索关键词的缓存键,确保不同q参数对应独立缓存:const { loading, data } = useQuery(FETCH_CARDS, { variables: { ...param }, notifyOnNetworkStatusChange: true, key: `search-cards-${param.keyword}` })修复useEffect依赖项
将param和data加入依赖数组,确保搜索参数变化、新数据返回时,同步更新页面状态:useEffect(() => { if (loading || !data) return setCards(data.cards) }, [loading, data, param])简化状态逻辑(可选)
直接使用useQuery返回的data,省去额外的useState,从根源避免状态不同步问题:export default function Waterfall({ param }: Props) { const { loading, data } = useQuery(FETCH_CARDS, { variables: { ...param }, notifyOnNetworkStatusChange: true }) if (loading) return <div>加载中...</div> return ( <div> {data?.cards.map((card) => ( <Card key={card._id} card={card} /> ))} </div> ) }Next.js路由缓存说明
- Next.js默认缓存静态生成的路由,但你的
/search是客户端组件,属于动态场景,路由参数变化会触发组件重新渲染,不会忽略搜索参数; - 若要针对不同搜索参数缓存页面,静态生成场景可使用
generateStaticParams,动态场景则通过Apollo的缓存配置即可实现不同参数结果的独立缓存,上述配置已满足需求。
- Next.js默认缓存静态生成的路由,但你的
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

