You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

疑问

  1. Next.js是否会缓存带搜索参数的路由?是否忽略了参数?
  2. 如何分别缓存/search?q=one和/search?q=two的内容?

原因与解决方案

问题根源

你的问题不是Next.js路由缓存导致的,而是Apollo Client缓存策略和组件状态更新逻辑的问题:

  • useQuery默认会缓存查询结果,若未配置正确的缓存标识,不同搜索参数可能复用旧缓存;
  • useEffect的依赖项只有initialLoading,当搜索关键词变化时,新的查询数据返回后无法触发状态更新,导致页面展示旧内容;
  • Next.js的App Router中,客户端组件会随路由参数变化重新渲染,但你的Waterfall组件没正确响应参数变化。

解决步骤

  1. 修正Apollo useQuery缓存配置
    给useQuery添加notifyOnNetworkStatusChange: true,并手动指定包含搜索关键词的缓存键,确保不同q参数对应独立缓存:

    const { loading, data } = useQuery(FETCH_CARDS, {
      variables: { ...param },
      notifyOnNetworkStatusChange: true,
      key: `search-cards-${param.keyword}`
    })
    
  2. 修复useEffect依赖项
    将param和data加入依赖数组,确保搜索参数变化、新数据返回时,同步更新页面状态:

    useEffect(() => {
      if (loading || !data) return
      setCards(data.cards)
    }, [loading, data, param])
    
  3. 简化状态逻辑(可选)
    直接使用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>
      )
    }
    
  4. Next.js路由缓存说明

    • Next.js默认缓存静态生成的路由,但你的/search是客户端组件,属于动态场景,路由参数变化会触发组件重新渲染,不会忽略搜索参数;
    • 若要针对不同搜索参数缓存页面,静态生成场景可使用generateStaticParams,动态场景则通过Apollo的缓存配置即可实现不同参数结果的独立缓存,上述配置已满足需求。

内容的提问来源于stack exchange,提问作者Ray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:15:18