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

如何让Adobe PDF Embed API在NextJS中正常运行(可尝试禁用SSR)

问题

我基于Create React App开发的React应用中,某页面通过Adobe PDF Embed API渲染PDF文件完全正常,但迁移到Next.js后,页面其他组件均能正常工作,唯独PDF渲染器失效——仅生成空的pdf-div容器,API应填充的PDF内容未显示。我需要让这个带完整功能的PDF查看器正常运行,曾推测是服务端渲染(SSR)问题,尝试过用高阶组件和Next.js动态导入禁用SSR,但未解决。

相关代码(/pages/notes/[id].tsx)

import { Flex, Heading, HStack, Link, Stack, Text, useColorMode, VStack } from "@chakra-ui/react";
import ReactGA from "react-ga4";
import { useEffect } from "react";
import { toast } from "react-hot-toast";
import { useDispatch, useSelector } from "react-redux";
import Loader from "../../components/Layout/Loader";
import ViewSDKClient from "../../others/ViewSDKClient";
import { getNotes } from "../../redux/actions/subject";
import { useRouter } from "next/router";

const Notes = () => {
  const dispatch = useDispatch();
  const { colorMode } = useColorMode();

  const router = useRouter();
  const { id } = router.query;

  const { notes, error, loading } = useSelector((state: any) => state.subjects);
  document.title = notes ? (notes.title + " - CollegeNotes") : "Loading - CollegeNotes";

  useEffect(() => {
    ReactGA.send({ hitType: "pageview", page: document.title + window.location.pathname });
  }, [notes])

  useEffect(() => {
    dispatch(getNotes(id) as any);
  }, [dispatch, id]);

  useEffect(() => {
    if (error) {
      toast.error(error);
      dispatch({ type: "clearError" });
    }
  }, [error, dispatch]);

  const loadPDF = () => {
    const viewSDKClient = new ViewSDKClient();
    viewSDKClient.ready().then(() => {
      viewSDKClient.previewFile(
        "pdf-div",
        {
          embedMode: window.innerWidth > 800 ? "SIZED_CONTAINER" : "FULL_WINDOW",
          showAnnotationTools: false,
          showPageControls: true,
          showDownloadPDF: false,
          showPrintPDF: false,
        },
        
        notes.document.url,
        notes.title
      );
    });
  };

  return (
    <>
      {loading || !notes ? (
        <Loader />
      ) : (
        <Flex
          minH={"100vh"}
          width={"100%"}
          direction={"row"}
          justifyContent={"space-around"}
        >
          <Stack
            height={"100%"}
            marginX={"3"}
            marginY={["8", "10", "12", "12", "14"]}
            width={"container.md"}
          >
            <Heading
              size={["xs", "sm"]}
              fontFamily={"Roboto Condensed"}
              children={notes.subject}
              textTransform={"uppercase"}
              paddingBottom={"2px"}
              borderBottom={"3px solid"}
              display={"inline"}
              width={"fit-content"}
            />

            <Heading
              as={"h1"}
              paddingTop={["1", "2"]}
              children={notes.title}
              fontFamily={"Source Serif Pro"}
              fontWeight={"extrabold"}
              size={["2xl", "3xl"]}
            />

            <HStack fontSize={"13px"}>
              <Text fontFamily={"Inter"} children={"Contributed by: "} />
              
              <Link
                target={"_blank"}
                fontFamily={"Inter"}
                color={ colorMode === "light" ? "teal.600" : "teal.300"}
                href={notes.contributorSocial}
              >
                {notes.contributor}
              </Link>
            </HStack>
            

            <Text
              fontSize={"md"}
              fontFamily={"Lusitana"}
              paddingTop={["4", "7"]}
              paddingBottom={["1", "3"]}
              children={notes.description}
            />

            <VStack width={"100%"}>
              <Flex
                id="pdf-div"
                height={"98vh"}
                onLoad={loadPDF()!}
              />
            </VStack>
          </Stack>
        </Flex>
      )}
    </>
  );
};

export default Notes;

解决方案

1. 修复onLoad的调用错误

当前代码中onLoad={loadPDF()!}是直接执行函数而非传递引用,会导致组件渲染时就调用loadPDF,此时DOM元素可能未挂载、notes数据也可能未就绪。应移除onLoad属性,改用useEffect控制加载时机。

2. 确保PDF加载逻辑仅在客户端执行

Adobe PDF Embed API依赖浏览器环境,将加载逻辑放在依赖notes的useEffect中,并添加客户端环境与DOM元素存在性判断:

useEffect(() => {
  if (!notes?.document?.url) return;
  if (typeof window === 'undefined') return;

  const viewSDKClient = new ViewSDKClient();
  viewSDKClient.ready().then(() => {
    const pdfDiv = document.getElementById("pdf-div");
    if (!pdfDiv) return;
    
    viewSDKClient.previewFile(
      "pdf-div",
      {
        embedMode: window.innerWidth > 800 ? "SIZED_CONTAINER" : "FULL_WINDOW",
        showAnnotationTools: false,
        showPageControls: true,
        showDownloadPDF: false,
        showPrintPDF: false,
      },
      notes.document.url,
      notes.title
    );
  });
}, [notes]);

3. 动态导入ViewSDKClient并禁用SSR

如果ViewSDKClient内部直接访问window对象,SSR时会报错,用Next.js的dynamic导入禁用SSR:

import dynamic from 'next/dynamic';

const ViewSDKClient = dynamic(() => import('../../others/ViewSDKClient'), {
  ssr: false,
  loading: () => <div>加载PDF查看器...</div>
});

替换原有的直接import语句。

4. 修正页面标题设置方式

Next.js中直接修改document.title可能在SSR阶段出错,改用next/head组件设置标题:

import Head from 'next/head';

// 在组件return的最外层添加
<Head>
  <title>{notes ? `${notes.title} - CollegeNotes` : "Loading - CollegeNotes"}</title>
</Head>

删除原代码中document.title = ...这一行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 00:42:17