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

Next.js使用SWR过滤博客数据时的两类异常问题排查

问题原因分析

切换标签后列表重置的原因

useSWR默认开启revalidateOnFocus配置,页面重新获得焦点时会自动用初始注册的请求key重拉数据。你当前的实现里,useSWR初始化的请求没有绑定选中的分类参数,过滤操作是脱离SWR手动写fetch、手动更新列表状态,和SWR自身的请求逻辑完全脱节。切回标签时SWR自动发起不带分类参数的请求,拿到全量数据后直接覆盖了你手动更新的列表,就会出现筛选状态重置的问题。

点击Blog链接不重置列表的原因

你做筛选跳转时用了shallow: true配置,不会触发页面组件的重新挂载。同时导航栏的Blog链接指向纯/blog路径时,Next.js会判定当前已经处于/blog路由下,不会主动重置组件状态,而你也没有写监听路由query变化的逻辑——当路由回到不带category参数的/blog路径时,没有代码触发清空筛选、拉取全量文章的操作,列表自然会停留在之前的筛选状态。


代码实现的核心错误
  • 违反useSWR的基本使用规则:动态请求参数(分类值)必须纳入SWR的缓存key,你脱离SWR手动维护请求和列表状态,直接导致SWR自带的焦点重验证、网络重连重验证逻辑和本地状态脱节。
  • 双状态源不同步:你同时维护了本地组件状态(博客列表、筛选值)和URL query两个状态源,没有指定唯一可信数据源,两边数据不一致必然触发异常。
  • shallow路由使用逻辑缺失:用shallow模式更新了URL参数,却没有配套处理路由参数变化时的数据拉取、状态重置逻辑。

修正后的实现方案

以URL query作为筛选状态的唯一可信来源,把分类参数直接绑定到SWR的请求key上,去掉冗余的手动fetch和手动状态更新:

import { useRouter } from 'next/router'
import useSWR from 'swr'

// 统一封装请求方法
const fetcher = (url) => fetch(url).then(res => res.json())

export default function BlogPage() {
  const router = useRouter()
  // 直接从URL读取当前分类,无参数时默认拉全量
  const currentCategory = router.query.category || ''

  // 分类参数纳入SWR key,参数变化时SWR自动发新请求
  const { data, isLoading } = useSWR(
    `${fetch_url}?category=${currentCategory}`,
    fetcher,
    { revalidateOnFocus: true } // 开焦点重验证也不会拉错数据
  )

  const blogItems = data?.blog_posts || []
  const nextPgLink = data?.next_pg_link || null

  // 筛选操作只做路由跳转,不手动发请求、不手动改列表状态
  const filterPosts = (category) => {
    const targetPath = category ? `/blog?category=${category}` : '/blog'
    router.push(targetPath, undefined, { shallow: true })
  }

  return (
    <div>
      {/* 下拉筛选控件 */}
      <select 
        value={currentCategory}
        onChange={(e) => filterPosts(e.target.value)}
      >
        <option value="">全部分类</option>
        <option value="frontend">前端</option>
        <option value="backend">后端</option>
        <option value="life">生活</option>
      </select>

      {/* 文章列表渲染 */}
      {isLoading ? 
        <div>加载中...</div> : 
        blogItems.map(post => <div key={post.id}>{post.title}</div>)
      }
    </div>
  )
}

该实现下不需要额外写重置逻辑:点导航栏/blog链接时URL的category参数被清空,SWR会自动拉取全量文章;切回标签触发重验证时,也会用当前URL上的分类参数发请求,不会出现状态错乱。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 00:57:55