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

NextJS动态导入未禁用服务端渲染 引入含window对象组件报错如何解决

你遇到的报错是两个核心原因导致的:

  1. React Hook调用规则违规:useAgora是自定义React Hook,你将它放在if (isBrowser)条件块中调用,违反了「Hook必须在组件顶层无条件调用」的规则,会导致Hook执行时序混乱,就算条件判断成立也可能出现异常。
  2. Next.js渲染规则适配问题:如果你使用的是Next 13+ App Router,未给客户端组件加'use client'指令的话,组件会默认被当做服务端组件处理,此时即便配置了ssr: false也可能在服务端被执行逻辑。另外你声明的async function Event()是非法的客户端组件写法,客户端组件不能为异步函数,会破坏动态导入的渲染逻辑。

步骤1:修复Event页面组件

首先移除页面组件的async声明,如果是App Router架构,在页面顶部添加'use client'指令:

// event.js
'use client' // App Router 必须加,Pages Router不用
import { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";

const NoSsrLiveStreaming = dynamic(
  () => import("@/components/ui/LiveStreaming"),
  {
    ssr: false,
    // 可选:加个loading组件避免加载时闪动
    loading: () => <div>加载中...</div>
  }
);

// 移除async声明
function Event() {
  return (
    <div suppressHydrationWarning={true}>
      <NoSsrLiveStreaming />
    </div>
  );
}

export default Event;

步骤2:修复LiveStreaming组件

首先确认isBrowser的实现是正确的:

const isBrowser = typeof window !== 'undefined'

然后调整Hook调用逻辑,不要在条件中调用useAgora,可以两种方案选其一:

方案A:修改useAgora内部做环境兼容

在useAgora自定义Hook的最开头加环境判断,非浏览器环境直接返回默认值:

// useAgora 钩子内部修改
function useAgora(client) {
  if (typeof window === 'undefined') {
    return {
      localAudioTrack: null,
      localVideoTrack: null,
      leave: () => {},
      join: () => {},
      joinState: false,
      remoteUsers: []
    }
  }
  // 原有逻辑
}

之后调整LiveStreaming组件代码,移除Hook调用的条件包裹:

// LiveStreaming.js
'use client' // App Router必须加
import { useState, useEffect } from 'react'
import AgoraRTC from 'agora-rtc-sdk'
import useAgora from '你的useAgora路径'

function LiveStreaming() {
  const [appid, setAppid] = useState("");
  const [token, setToken] = useState("");
  const [channel, setChannel] = useState("");
  const [client, setClient] = useState(null);

  // 顶层无条件调用Hook
  const agoraObj = useAgora(client);
  const {
    localAudioTrack,
    localVideoTrack,
    leave,
    join,
    joinState,
    remoteUsers
  } = agoraObj;

  // client初始化放到useEffect中,仅客户端挂载后执行
  useEffect(() => {
    if (!isBrowser) return
    const newClient = AgoraRTC.createClient({ codec: "h264", mode: "rtc" });
    setClient(newClient)
  }, [])

  // 原有其他逻辑
}
export default LiveStreaming

方案B:不用修改useAgora,把Agora相关逻辑全部放到子组件+useEffect中

如果你不想修改useAgora的代码,可以拆分组件,把用到useAgora的逻辑放到内层组件,仅在客户端挂载后才渲染内层组件:

// LiveStreaming.js
'use client'
import { useState, useEffect } from 'react'

function LiveStreaming() {
  const [isClient, setIsClient] = useState(false)

  useEffect(() => {
    setIsClient(true)
  }, [])

  // 未到客户端挂载阶段直接返回null
  if (!isClient) return null

  // 客户端阶段才渲染真正的直播逻辑,此时100%有window对象
  return <LiveStreamingCore />
}

// 内层核心组件,只有客户端才会渲染
function LiveStreamingCore() {
  const [appid, setAppid] = useState("");
  const [token, setToken] = useState("");
  const [channel, setChannel] = useState("");
  // 这里直接初始化client和调用Hook,不需要条件判断,因为只会在客户端执行
  const client = AgoraRTC.createClient({ codec: "h264", mode: "rtc" });
  const agoraObj = useAgora(client);
  const {
    localAudioTrack,
    localVideoTrack,
    leave,
    join,
    joinState,
    remoteUsers
  } = agoraObj;

  // 原有逻辑
}

可选兜底方案:动态导入Agora SDK本身

如果还是有问题,可以直接把AgoraRTC的导入也改成动态导入,确保不会在服务端被加载:

useEffect(() => {
  const initAgora = async () => {
    const AgoraRTC = (await import('agora-rtc-sdk')).default
    // 后续初始化逻辑
  }
  initAgora()
}, [])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:06:06