Next.js动态路由使用useSWR+Firebase获取实时数据偶现失败
问题根因分析
- 初始状态未定义:你声明
const [poolState, setPoolState] = useState()没有传初始值,首次渲染时poolState为undefined,此时如果直接读取poolState的属性或数组元素就会抛出未定义错误 - 动态路由参数未就绪:Next.js Pages Router 的
router.query在页面首次hydration完成前是未赋值的,此时sPoolPage为undefined,你的匹配逻辑无法命中对应池子数据 - useEffect依赖缺失:你当前的useEffect仅监听了
data变化,未监听sPoolPage,如果sPoolPage晚于接口数据返回才解析完成,不会重新触发匹配逻辑,导致poolState始终为空 - 全量拉取数据再过滤效率低:无需拉取所有池子数据后再本地过滤,Google Realtime Database支持直接请求单个节点数据
修复方案
你可以直接优化为更精简的实现,去掉冗余的useState和useEffect,利用SWR的条件请求能力避免无效请求:
import PoolDetails from "../../components/PoolDetails"; import { Fragment } from "react"; import useSWR from "swr"; import { useRouter } from "next/router"; const fetcher = (...args) => fetch(...args).then((res) => res.json()); export default function SinglePoolPage(props) { const router = useRouter(); const { sPoolPage } = router.query; // 条件请求:仅当sPoolPage存在时才发起请求 const { data: poolData, error, isLoading } = useSWR( sPoolPage ? `https://samplefirebasebackendurl.app/pools/${sPoolPage}.json` : null, fetcher, { // 配置实时更新间隔,根据你的需求调整,单位毫秒 refreshInterval: 1000, revalidateOnFocus: true // 窗口聚焦时自动重新拉取数据保证最新 } ); // 加载状态处理 if (isLoading) return <div>数据加载中...</div>; // 错误状态处理 if (error) return <div>数据加载失败,请刷新重试</div>; // 池子不存在处理 if (!poolData) return <div>当前池子不存在</div>; return ( <Fragment> <PoolDetails id={sPoolPage} name={poolData.name} timer={poolData.timer} /> </Fragment> ); }
改动说明
- 移除了冗余的本地状态
poolState和useEffect匹配逻辑,直接复用SWR返回的接口数据,减少多余渲染 - 新增条件请求,确保动态路由参数就绪后才发起接口请求,避免无效请求和匹配失败
- 直接请求对应池子的独立节点,减少数据传输量,提升加载速度
- 新增了加载、错误、无数据三种边界状态处理,避免渲染时读取未定义数据
- 新增SWR实时更新配置,满足数据频繁变动的实时展示需求,无需手动处理轮询逻辑
内容的提问来源于stack exchange,提问作者CondorW
相关产品推荐
相关产品推荐

