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

Next.js 13 Beta客户端组件出现document is not defined错误求助

解决Next.js 13中ReactQuill报"document is not defined"的问题

问题根源

在Next.js 13的App Router里,就算给组件加了'use client'标记,模块导入阶段的代码仍会在服务器端执行。ReactQuill在模块初始化时就调用了document对象,而服务器环境不存在document,所以直接抛出错误。你useEffect里的代码能正常运行,是因为useEffect本身只在客户端执行。


解决方案1:Next.js动态导入(推荐)

用next/dynamic动态导入ReactQuill并禁用SSR,确保组件仅在客户端加载执行:

'use client'
import React, { useState } from 'react';
import dynamic from 'next/dynamic';

// 动态导入ReactQuill,禁用服务器端渲染
const ReactQuill = dynamic(() => import('react-quill'), {
  ssr: false,
  loading: () => <div>编辑器加载中...</div> // 可选:添加加载状态提示
});

// 客户端环境导入样式文件
import 'react-quill/dist/quill.snow.css';

const Editor = ({ placeholder }) => {
  const [editorHtml, setEditorHtml] = useState('');
  const [theme, setTheme] = useState('snow');

  useEffect(() => {
    console.log(document.location.href)
  }, [])

  return (
    <div>
      <ReactQuill
        theme={theme}
        value={editorHtml}
        onChange={setEditorHtml}
        modules={Editor.modules}
        formats={Editor.formats}
        bounds={'.app'}
        placeholder={placeholder}
      />
    </div>
  );
};

// 配置编辑器工具栏和格式
Editor.modules = {
  toolbar: [
    ['bold', 'italic', 'underline', 'strike'],
    ['blockquote', 'code-block'],
    [{ 'header': 1 }, { 'header': 2 }],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }],
    [{ 'color': [] }, { 'background': [] }],
    ['link', 'image'],
    ['clean']
  ]
};

Editor.formats = [
  'bold', 'italic', 'underline', 'strike',
  'blockquote', 'code-block',
  'header', 'list', 'color', 'background',
  'link', 'image'
];

export default Editor;

解决方案2:条件渲染(仅客户端渲染组件)

通过状态控制ReactQuill仅在客户端挂载后渲染,避免服务器端执行组件代码:

'use client'
import React, { useState, useEffect } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

const Editor = ({ placeholder }) => {
  const [editorHtml, setEditorHtml] = useState('');
  const [theme, setTheme] = useState('snow');
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    // 客户端挂载后标记为已在客户端环境
    setIsClient(true);
    console.log(document.location.href)
  }, [])

  return (
    <div>
      {/* 仅在客户端环境渲染ReactQuill */}
      {isClient && (
        <ReactQuill
          theme={theme}
          value={editorHtml}
          onChange={setEditorHtml}
          modules={Editor.modules}
          formats={Editor.formats}
          bounds={'.app'}
          placeholder={placeholder}
        />
      )}
    </div>
  );
};

// 配置编辑器工具栏和格式
Editor.modules = {
  toolbar: [
    ['bold', 'italic', 'underline', 'strike'],
    ['blockquote', 'code-block'],
    [{ 'header': 1 }, { 'header': 2 }],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }],
    [{ 'color': [] }, { 'background': [] }],
    ['link', 'image'],
    ['clean']
  ]
};

Editor.formats = [
  'bold', 'italic', 'underline', 'strike',
  'blockquote', 'code-block',
  'header', 'list', 'color', 'background',
  'link', 'image'
];

export default Editor;

解决方案3:封装客户端专用组件

把ReactQuill封装到单独的客户端组件中,再通过动态导入使用:

  1. 创建components/ClientQuill.tsx:
'use client';

import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

export default ReactQuill;
  1. 在app/editor/page.tsx中动态导入:
'use client'
import React, { useState } from 'react';
import dynamic from 'next/dynamic';

const ClientQuill = dynamic(() => import('@/components/ClientQuill'), {
  ssr: false,
  loading: () => <div>编辑器加载中...</div>
});

const Editor = ({ placeholder }) => {
  const [editorHtml, setEditorHtml] = useState('');
  const [theme, setTheme] = useState('snow');

  useEffect(() => {
    console.log(document.location.href)
  }, [])

  return (
    <div>
      <ClientQuill
        theme={theme}
        value={editorHtml}
        onChange={setEditorHtml}
        modules={Editor.modules}
        formats={Editor.formats}
        bounds={'.app'}
        placeholder={placeholder}
      />
    </div>
  );
};

// 配置编辑器工具栏和格式
Editor.modules = {
  toolbar: [
    ['bold', 'italic', 'underline', 'strike'],
    ['blockquote', 'code-block'],
    [{ 'header': 1 }, { 'header': 2 }],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }],
    [{ 'color': [] }, { 'background': [] }],
    ['link', 'image'],
    ['clean']
  ]
};

Editor.formats = [
  'bold', 'italic', 'underline', 'strike',
  'blockquote', 'code-block',
  'header', 'list', 'color', 'background',
  'link', 'image'
];

export default Editor;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:10:21