在React Query数据获取中是否需要使用router.isReady?
解决Next.js中React Query结合动态路由的查询触发时机问题
你的核心问题是React Query在路由参数就绪前就发起了请求,导致artistId为undefined,同时你额外用useState维护数据状态完全是冗余操作——React Query本身就负责数据缓存和状态管理。下面是优化后的完整方案:
关键优化点
- 用useQuery的
enabled选项控制查询触发时机,仅当路由就绪且artistId存在时才执行 - 移除多余的
useState和关联useEffect,直接使用React Query返回的data和status - 更新查询键为
["artist", artistId],确保不同艺术家的缓存相互独立 - 简化路由守卫逻辑,无需额外空
useEffect检查路由状态
修改后的代码
pages/artist/[artistId].js
import React, { useEffect } from "react"; import { useSession } from "next-auth/react"; import { useRouter } from "next/router"; import { useQuery } from "@tanstack/react-query"; import Head from "next/head"; import ArtistHeader from "../../components/ArtistHeader"; import UploadButton from "../../components/UploadButton"; import fetchArtist from "../../hooks/getArtists"; import styles from "../../styles/artistPage.module.css"; export default function Artist() { const { status } = useSession(); const router = useRouter(); const { artistId } = router.query; // 路由守卫:未认证时跳转登录页 useEffect(() => { if (status === "unauthenticated") { router.push("/auth/signin"); } }, [status, router]); // React Query 数据查询:仅当路由就绪且artistId存在时触发 const { data: artist, status: artistStatus } = useQuery( ["artist", artistId], // 加入artistId作为查询键,区分不同艺术家的缓存 () => fetchArtist(artistId), { enabled: router.isReady && !!artistId, // 控制查询触发时机 staleTime: 1000 * 60 * 60 * 24, cacheTime: 1000 * 60 * 60 * 24, } ); // 加载状态处理(可选) if (artistStatus === "loading") { return <div className={styles.wrapper}>加载中...</div>; } // 无数据处理(可选) if (!artist) { return <div className={styles.wrapper}>未找到艺术家信息</div>; } return ( <section className={styles.wrapper}> <Head> <title>{artist.screenName}</title> </Head> <div className={styles.artistPage}> <ArtistHeader artist={artist} /> <div className={styles.songContainer}> <UploadButton /> </div> </div> </section> ); }
hooks/getArtists.js(可选优化:增加参数校验)
import { getDoc, doc } from "firebase/firestore"; import { db } from "../pages/api/auth/firebase/config"; export default async function fetchArtist(artistId) { // 新增参数校验,避免无效请求 if (!artistId) { throw new Error("artistId 参数不能为空"); } const artistRef = doc(db, "users", artistId); const artistDoc = await getDoc(artistRef); if (artistDoc.exists()) { return artistDoc.data(); } else { console.log("No such document!"); return null; // 明确返回null,方便组件处理无数据情况 } }
为什么这样改?
enabled选项是React Query控制查询执行的核心,只有当该值为true时,查询才会发起,完美解决路由参数未就绪的问题- 查询键加入
artistId后,不同艺术家的数据会被分别缓存,不会出现数据混淆 - 直接使用
data: artist替代useState,减少不必要的状态同步,让React Query完全接管数据生命周期 - 增加加载和无数据状态的处理,提升用户体验
内容的提问来源于stack exchange,提问作者Yan
相关产品推荐
相关产品推荐

