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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:55:23