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

Next.js中MSW首次渲染无法连接API的问题求助

在Next.js中解决MSW初始化晚于首次渲染导致的API请求失败问题

核心问题分析

你的问题本质是MSW的客户端初始化时机滞后于React Query首次请求发起的时机,加上Next.js的SSR/SSG特性,服务器端不会执行MSW代码,客户端Hydration阶段如果请求先触发,就会直接打真实API导致失败,进而触发Next.js的_error页面编译。

下面给出几种针对性的解决方法:


方法1:在_app.tsx(Pages Router)中确保MSW客户端优先初始化

利用Next.js的_app.tsx作为全局入口,通过动态导入+状态标记确保MSW只在客户端初始化,且完成后再渲染页面内容:

// pages/_app.tsx
import { useEffect, useState } from 'react'
import type { AppProps } from 'next/app'

function MyApp({ Component, pageProps }: AppProps) {
  const [mswReady, setMswReady] = useState(false)

  useEffect(() => {
    // 仅在客户端环境执行,动态导入避免服务器端加载MSW
    if (!mswReady && typeof window !== 'undefined') {
      import('../mocks').then(() => {
        setMswReady(true)
      })
    }
  }, [mswReady])

  // 等待MSW初始化完成后再渲染页面组件
  if (!mswReady) {
    return <div>Initializing service worker...</div>
  }

  return <Component {...pageProps} />
}

export default MyApp

方法2:给React Query请求加条件触发(适配Pages/App Router)

在发起请求的页面组件中,通过状态监听MSW的初始化状态,仅当MSW准备就绪后再激活React Query请求:

步骤1:修改MSW初始化代码,添加就绪通知

// mocks/index.ts
import { setupWorker } from 'msw'
import { handlers } from './handlers'

const worker = setupWorker(...handlers)

// 初始化完成后触发自定义事件,通知页面组件
worker.start().then(() => {
  if (typeof window !== 'undefined') {
    window.dispatchEvent(new CustomEvent('msw:initialized'))
  }
})

步骤2:页面组件中监听状态,控制请求触发

// pages/index.tsx 或 app/page.tsx(需加'use client')
'use client'

import { useQuery } from '@tanstack/react-query'
import axios from 'axios'
import { useEffect, useState } from 'react'

export default function Home() {
  const [isMswReady, setIsMswReady] = useState(false)

  useEffect(() => {
    // 监听MSW初始化完成事件
    const handleMswReady = () => setIsMswReady(true)
    window.addEventListener('msw:initialized', handleMswReady)

    // 兜底检查:如果MSW已提前初始化
    if (window.msw?.worker?.isReady) {
      setIsMswReady(true)
    }

    return () => window.removeEventListener('msw:initialized', handleMswReady)
  }, [])

  // 仅当MSW就绪后才发起请求
  const { data, error } = useQuery({
    queryKey: ['your-api-data'],
    queryFn: () => axios.get('/api/your-endpoint').then(res => res.data),
    enabled: isMswReady
  })

  if (!isMswReady) {
    return <div>Loading...</div>
  }

  if (error) {
    return <div>请求错误:{error.message}</div>
  }

  return <div>请求结果:{JSON.stringify(data)}</div>
}

方法3:App Router下的客户端组件初始化

如果你使用Next.js 13+的App Router,直接在根layout或页面组件中标记为客户端组件,然后同步初始化MSW:

// app/layout.tsx
'use client'

import { useEffect } from 'react'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  useEffect(() => {
    // 仅在客户端初始化MSW
    import('../mocks')
  }, [])

  return (
    <html lang="zh-CN">
      <body>{children}</body>
    </html>
  )
}

额外注意事项

  1. 确保你的MSW handlers配置正确,特别是请求路径、方法与真实API一致;
  2. 终端的compiling /_error (client and server)错误是请求失败触发的,解决MSW初始化问题后该错误会自动消失;
  3. 开发环境下建议禁用React Query的重试机制,避免多次触发无效请求:
// React Query配置中添加
retry: 0

内容的提问来源于stack exchange,提问作者MR.Jeon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 07:26:07