NextJS中导入React Quill的ui/icons时出现document未定义错误
解决React Quill在Next.js中修改图标时出现"document is not defined"的问题
问题原因
Next.js是服务端渲染(SSR)框架,组件代码会先在服务端执行一遍,但服务端环境没有document对象。你直接在组件函数中调用Quill.import('ui/icons'),这部分代码会在服务端运行时触发错误,因为Quill的UI模块依赖浏览器的DOM环境。
解决方案
核心思路是确保Quill的图标修改逻辑只在客户端执行,以下是两种可行的实现方式:
方式一:使用useEffect处理图标修改
useEffect钩子仅在客户端渲染时执行,能避开服务端环境的限制:
import { Stack } from '@mui/material' import * as React from 'react' import { useMemo, useState, useEffect } from 'react' import ReactDOM from 'react-dom' import 'react-quill/dist/quill.snow.css' import dynamic from 'next/dynamic' import { RedoIcon } from 'libs/icons' interface Props {} const modules = { toolbar: [ ['undo', 'redo'], ['bold', 'italic', 'underline', 'strike'], ['blockquote', 'code-block'], ] } const CustomQuill = () => { const [value, setValue] = useState('') const ReactQuill = useMemo(() => dynamic(() => import('react-quill'), { ssr: false }), []) useEffect(() => { // 仅在客户端环境执行Quill相关操作 const { Quill } = require('react-quill') const icons = Quill.import('ui/icons') // 注意:Quill图标需要DOM元素/HTML字符串,不能直接传React组件,需转换 const iconContainer = document.createElement('div') ReactDOM.render(<RedoIcon />, iconContainer) icons['undo'] = iconContainer.firstChild // 注册修改后的图标 Quill.register('ui/icons', icons, true) }, []) return ( <Stack> {typeof window !== 'undefined' && ( <ReactQuill value={value} onChange={setValue} modules={modules} /> )} </Stack> ) } export default CustomQuill
方式二:在动态导入ReactQuill时处理图标
利用dynamic的ssr: false配置,确保图标修改逻辑仅在客户端执行:
import { Stack } from '@mui/material' import * as React from 'react' import { useMemo, useState } from 'react' import ReactDOM from 'react-dom' import 'react-quill/dist/quill.snow.css' import dynamic from 'next/dynamic' import { RedoIcon } from 'libs/icons' interface Props {} const modules = { toolbar: [ ['undo', 'redo'], ['bold', 'italic', 'underline', 'strike'], ['blockquote', 'code-block'], ] } const CustomQuill = () => { const [value, setValue] = useState('') // 动态导入时同时修改图标 const ReactQuill = useMemo(() => dynamic(() => import('react-quill').then((module) => { const { Quill } = module const icons = Quill.import('ui/icons') // 转换React组件为DOM元素 const iconContainer = document.createElement('div') ReactDOM.render(<RedoIcon />, iconContainer) icons['undo'] = iconContainer.firstChild Quill.register('ui/icons', icons, true) return module.default }) , { ssr: false }), []) return ( <Stack> {typeof window !== 'undefined' && ( <ReactQuill value={value} onChange={setValue} modules={modules} /> )} </Stack> ) } export default CustomQuill
关键注意点
- 不要在组件顶部或服务端可执行的代码块中直接调用Quill的UI相关API,必须限制在客户端上下文。
- Quill的图标不支持直接传入React组件,需要通过
ReactDOM.render将组件转换为DOM元素,或者直接使用图标对应的SVG HTML字符串。
内容的提问来源于stack exchange,提问作者Quân Phùng
相关产品推荐
相关产品推荐

