Uppy在Next.js中报"document is not defined"错误的解决办法
在Next.js中集成Uppy的解决方案
Next.js的服务端渲染环境没有document、window这类浏览器API,而Uppy依赖这些API运行,下面是几种可行的解决办法:
方法1:动态导入并禁用SSR(推荐)
用Next.js自带的next/dynamic工具,将Uppy相关组件设置为仅客户端加载,避免服务端渲染时触发API缺失错误。
步骤:
- 创建单独的Uppy组件文件(比如
UppyUploader.tsx),在里面正常初始化Uppy:
import Uppy from '@uppy/core'; import DragDrop from '@uppy/drag-drop'; import '@uppy/core/dist/style.min.css'; import '@uppy/drag-drop/dist/style.min.css'; import { useEffect, useRef } from 'react'; export default function UppyUploader() { const uppyRef = useRef<Uppy | null>(null); useEffect(() => { // 初始化Uppy实例 if (!uppyRef.current) { const uppy = new Uppy() .use(DragDrop, { target: '#drag-drop-area' }); uppy.on('complete', (result) => { console.log('上传完成:', result.successful); }); uppyRef.current = uppy; } // 组件卸载时清理实例,避免内存泄漏 return () => { uppyRef.current?.close(); }; }, []); return ( <div id="drag-drop-area"> <p>拖放文件到这里,或点击选择文件</p> </div> ); }
- 在页面文件(比如
page.tsx)中动态导入该组件,设置ssr: false:
import dynamic from 'next/dynamic'; const UppyComponent = dynamic(() => import('./UppyUploader'), { ssr: false, loading: () => <p>加载上传组件中...</p> }); export default function Home() { return ( <div> <h1>文件上传</h1> <UppyComponent /> </div> ); }
方法2:通过环境判断仅在客户端初始化
如果不想拆分组件,可以在页面代码中通过typeof window !== 'undefined'判断当前环境,只在客户端执行Uppy的初始化逻辑:
import Uppy from '@uppy/core'; import DragDrop from '@uppy/drag-drop'; import '@uppy/core/dist/style.min.css'; import '@uppy/drag-drop/dist/style.min.css'; import { useEffect, useRef } from 'react'; export default function Home() { const uppyRef = useRef<Uppy | null>(null); useEffect(() => { // 仅在浏览器环境中初始化Uppy if (typeof window !== 'undefined' && !uppyRef.current) { const uppy = new Uppy() .use(DragDrop, { target: '#drag-drop-area' }); uppy.on('complete', (result) => { console.log('上传结果:', result); }); uppyRef.current = uppy; } return () => { uppyRef.current?.close(); }; }, []); return ( <div> <h1>文件上传</h1> <div id="drag-drop-area">拖放文件到这里上传</div> </div> ); }
方法3:Next.js 13+ App Router 用"use client"指令
如果你用的是Next.js 13及以上的App Router,直接在Uppy组件顶部加上'use client'标记,该组件就会被视为纯客户端组件,不会在服务端渲染:
UppyUploader.tsx:
'use client'; import Uppy from '@uppy/core'; import DragDrop from '@uppy/drag-drop'; import '@uppy/core/dist/style.min.css'; import '@uppy/drag-drop/dist/style.min.css'; import { useEffect, useRef } from 'react'; export default function UppyUploader() { const uppyRef = useRef<Uppy | null>(null); useEffect(() => { if (!uppyRef.current) { const uppy = new Uppy() .use(DragDrop, { target: '#drag-drop-area' }); uppyRef.current = uppy; } return () => { uppyRef.current?.close(); }; }, []); return <div id="drag-drop-area">拖放文件到这里</div>; }
page.tsx:
import UppyUploader from './UppyUploader'; export default function Home() { return ( <main> <h1>文件上传页面</h1> <UppyUploader /> </main> ); }
内容的提问来源于stack exchange,提问作者Xen_mar
相关产品推荐
相关产品推荐

