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

React Query预取数据正常,重取/失效触发RangeError栈溢出

问题描述

首次渲染时,预取的数据可正常加载(react-query工具中可见);但尝试重新获取数据或使查询失效时,会触发RangeError: Maximum call stack size exceeded错误。所有同类自定义useFetch钩子均存在该问题。尝试将fetchFilters改为Server Action时,系统提示响应数据格式不符合要求。


相关代码

app/api/filters.ts

import type { TFilterData, TFilterDataResponse } from '@/lib/types'

import { baseURL } from './constants'
import { get } from './apiClient'

export const fetchFilters = async (): Promise<TFilterData> => {
  try {
    const path = `${baseURL}/api/dashboard/ratings/filter-options`
    const response = await get<TFilterDataResponse>(path)

    return response?.data?.data ?? {}
  } catch (error) {
    console.error('Error fetching filters:', error)
    throw error
  }
}

app/lib/hooks/useFilters.ts

'use client'

import { fetchFilters } from '@/app/api/filtersApi'
import { useQuery, keepPreviousData } from '@tanstack/react-query'

export const useFilters = () => {
  const {
    data: filters,
    isLoading: isLoadingFilters,
    error: errorFilters,
  } = useQuery({
    queryKey: ['filters'],
    queryFn: fetchFilters,
    placeholderData: keepPreviousData,
  })

  if (errorFilters) {
    console.log(
      '%cGET FILTERS',
      'background: red; color: white; padding: 2px;',
      errorFilters.message
    )
  }

  return {
    filters,
    isLoadingFilters,
    errorFilters,
  }
}

app/dashboard/DashboardClient.tsx

'use client'
const {
  filters: fullListFilters,
  isLoadingFilters,
  errorFilters,
} = useFilters()

app/dashboard/page.tsx

'use server'
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
  queryKey: ['filters'],
  queryFn: fetchFilters,
})
const dehydrateState = dehydrate(queryClient)
return (
  <HydrationBoundary state={dehydrateState}>
    <DashboardClient />
  </HydrationBoundary>
)

解决方案

1. 排查keepPreviousData引发的循环

keepPreviousData可能在特定场景下触发无限渲染循环,尤其是当数据结构存在引用循环或查询配置重复触发请求时。先移除该配置测试:

// 修改useFilters.ts中的useQuery配置
export const useFilters = () => {
  const {
    data: filters,
    isLoading: isLoadingFilters,
    error: errorFilters,
  } = useQuery({
    queryKey: ['filters'],
    queryFn: fetchFilters,
    // 暂时移除placeholderData: keepPreviousData
  })

  // 其余代码不变
}

2. 修复Server Action数据格式问题

转为Server Action时,需确保返回数据符合RSC序列化规则:

  • 排除函数、Symbol、循环引用等无法序列化的类型
  • 在返回前手动校验序列化可行性:
// 改为Server Action版本(app/actions/filters.ts)
'use server'

import type { TFilterData, TFilterDataResponse } from '@/lib/types'
import { baseURL } from '@/app/api/constants'
import { get } from '@/app/api/apiClient'

export const fetchFilters = async (): Promise<TFilterData> => {
  try {
    const path = `${baseURL}/api/dashboard/ratings/filter-options`
    const response = await get<TFilterDataResponse>(path)
    const data = response?.data?.data ?? {}
    
    // 校验序列化,提前发现问题
    JSON.stringify(data)
    return data
  } catch (error) {
    console.error('Error fetching filters:', error)
    throw error
  }
}

3. 统一服务端与客户端Query Client配置

确保服务端预取和客户端使用的Query Client配置一致,避免缓存策略冲突:

// app/dashboard/page.tsx
'use server'
import { QueryClient } from '@tanstack/react-query'

// 统一创建Query Client的逻辑
const createQueryClient = () => new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60 * 1000, // 匹配客户端默认设置
    },
  },
})

const queryClient = createQueryClient()

await queryClient.prefetchQuery({
  queryKey: ['filters'],
  queryFn: fetchFilters,
})
const dehydrateState = dehydrate(queryClient)
return (
  <HydrationBoundary state={dehydrateState}>
    <DashboardClient />
  </HydrationBoundary>
)

4. 检查数据中的循环引用

栈溢出最常见原因是数据存在循环引用,React Query递归处理时会触发无限递归。可添加检测逻辑:

// 在fetchFilters返回前检查
const data = response?.data?.data ?? {}
// 使用circular-json库检测循环引用
import CircularJSON from 'circular-json'
try {
  CircularJSON.stringify(data)
} catch (e) {
  console.error('数据包含循环引用:', e)
  // 手动清理循环引用属性,比如delete data.someCircularProp
}
return data

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:33:24