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

如何优化含异步API调用的React页面?useEffect依赖router.query场景

React + Next.js 客户端异步请求优化方案

以下方案均为客户端侧发起请求,API返回的set-cookie会正常写入客户端浏览器,符合你无法使用getServerSideProps的场景限制。

1 基础修复版:解决原实现的隐性问题

注意:useEffect 不允许直接传入 async 函数,会导致内存泄漏警告,因为 React 期望 useEffect 的返回值是清理函数而非 Promise。

同时新增router.isReady判断,确保路由 hydration 完成后再读取query,避免 hydration 过程中query为空导致的逻辑异常,修复后代码如下:

const MyPage = () => {
  const [user, setUser] = useState(null)
  const router = useRouter()

  useEffect(() => {
    // 路由未初始化完成/query无有效值直接跳过
    if (!router.isReady || !router.query.something) return

    const fetchUser = async () => {
      try {
        const res = await api.get(`/resetTokens/${router.query.something}`)
        setUser(res.data)
      } catch (err) {
        setUser(null)
      }
    }
    fetchUser()
  }, [router.isReady, router.query.something])

  return (<div>...</div>)
}

2 可复用封装:自定义请求Hook

如果项目中有多个同类场景,可以把逻辑抽成通用自定义Hook,页面代码会大幅简化:

// 全局通用Hook,可复用到所有依赖路由query的客户端请求场景
const useQueryByRouteParam = (paramKey, fetcher) => {
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)
  const router = useRouter()

  useEffect(() => {
    if (!router.isReady || !router.query[paramKey]) return
    const fetchData = async () => {
      try {
        const result = await fetcher(router.query[paramKey])
        setData(result)
      } catch (err) {
        setError(err)
        setData(null)
      }
    }
    fetchData()
  }, [router.isReady, router.query[paramKey], fetcher])

  return { data, error }
}

// 页面内使用
const MyPage = () => {
  const { data: user } = useQueryByRouteParam('something', async (something) => {
    const res = await api.get(`/resetTokens/${something}`)
    return res.data
  })

  return (<div>...</div>)
}

3 生产级最优解:使用专业数据请求库

如果项目允许引入SWR 或 TanStack Query(原React Query)这类数据请求库,无需手动维护状态、处理竞态、防重复请求,写法最简洁且稳定性最高:

以SWR为例:

import useSWR from 'swr'

const MyPage = () => {
  const router = useRouter()
  // SWR会自动跳过null值的请求,无需手动判断拦截
  const { data: user, error, isLoading } = useSWR(
    router.isReady && router.query.something ? `/resetTokens/${router.query.something}` : null,
    (url) => api.get(url).then(res => res.data)
  )

  // 自带加载、错误状态,不用额外写state维护
  if (isLoading) return <div>加载中</div>
  if (error) return <div>请求失败</div>

  return (<div>...</div>)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 10:36:04