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

React中Tiptap编辑器编辑超3000字页面冻结无响应原因排查

React中Tiptap编辑器内容超3000字时页面冻结无响应的原因排查

问题描述

在React项目中使用Tiptap编辑器,当编辑内容超过3000字时,页面出现冻结、无响应的情况。
Unresponsive Page

补充信息

  • PS(1):猜测问题可能出在useState上,大量使用useState并基于它渲染组件,例如:
{ canPost && <Component/>}
  • PS(2):移除使用useState的组件后,页面仍然崩溃。

编辑器扩展代码

//// Node TipTap Extensions
import Document from "@tiptap/extension-document";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";

// mark tipap extension
import Bold from "@tiptap/extension-bold";
import Code from "@tiptap/extension-code";
import Highlight from "@tiptap/extension-highlight";
import Italic from "@tiptap/extension-italic";
import Link from "@tiptap/extension-link";
import Strike from "@tiptap/extension-strike";
import Underline from "@tiptap/extension-underline";

// other tiptap extensions
import Dropcursor from "@tiptap/extension-dropcursor";
import Gapcursor from "@tiptap/extension-gapcursor";
import History from "@tiptap/extension-history";
import Placeholder from "@tiptap/extension-placeholder";
import Related from "@/lib/tiptap/related";
import { TipTapImage } from "@/lib/tiptap/image";

// Block TipTap Extensions
import Ads from "@/lib/tiptap/ads";
import Blockquote from "@tiptap/extension-blockquote";
import CodeBlock from "@tiptap/extension-code-block";
import BulletList from "@tiptap/extension-bullet-list";
import ListItem from "@tiptap/extension-list-item";
import HardBreak from "@tiptap/extension-hard-break";
import Heading from "@tiptap/extension-heading";
import HorizontalRule from "@tiptap/extension-horizontal-rule";
import OrderedList from "@tiptap/extension-ordered-list";
import Table from "@tiptap/extension-table";
import TableCell from "@tiptap/extension-table-cell";
import TableHeader from "@tiptap/extension-table-header";
import TableRow from "@tiptap/extension-table-row";
import Youtube from "@tiptap/extension-youtube";
import Video from "@/lib/tiptap/video";
export const editorExtensions = [
  Ads,
  Bold,
  Blockquote,
  BulletList,
  Code,
  CodeBlock,
  Document,
  Dropcursor,
  Gapcursor,
  HardBreak,
  Heading.configure({
    levels: [2, 3, 4, 5, 6],
  }),
  HorizontalRule,
  Highlight,
  History,
  Italic,
  Link.configure({
    openOnClick: false,
    HTMLAttributes: {
      rel: null,
    },
  }),
  ListItem,
  OrderedList,
  Paragraph,
  Placeholder.configure({
    placeholder:
      "Mulai menulis artikel dengan membaca bismillah dan akhiri dengan kata alhamdulillah, insya allah berkah...",
  }),
  Related,
  Strike,
  TableRow,
  TableCell,
  TableHeader,
  Table.configure({
    resizable: true,
  }),
  Text,
  TipTapImage.configure({
    HTMLAttributes: {
      loading: "lazy",
      width: "auto",
      height: "auto",
      sizes: "(max-width: 500px) 320px, (max-width: 1320px) 640px, 1280px",
      class: `h-auto w-full`,
    },
  }),
  Underline,
  Video,
  Youtube.configure({
    HTMLAttributes: {
      class: "youtube",
      loading: "lazy",
      height: "320",
      width: "640",
    },
  }),
];

useEditor配置代码

const editor = useEditor({
    extensions: editorExtensions,
    content: data?.content || "",
    editorProps: {
      attributes: {
        class:
          "prose w-full focus:outline-none prose-primary-600 min-h-[320px] max-w-none",
      },
    },
  });

问题原因及解决方案

1. 自定义扩展的性能瓶颈

你使用了多个自定义扩展(Ads、Related、TipTapImage、Video),这些扩展如果未做性能优化,比如在update或render阶段执行大量同步计算,内容增多时会阻塞主线程。

  • 排查方向:检查自定义扩展的render、update或addNodeView方法,避免在这些阶段执行循环遍历、DOM操作或数据转换等耗时操作。
  • 优化方案:对复杂计算做防抖/节流处理,或把非必要逻辑移到异步任务中。

2. Table扩展的resize性能问题

启用了Table.configure({ resizable: true })后,当表格行列数多且内容量大时,resize监听会频繁触发重计算,导致页面卡顿。

  • 优化方案:暂时关闭表格可调整大小功能,或给resize事件添加节流处理;若必须保留resize,限制表格最大行列数。

3. Prose样式的重排重绘开销

编辑器容器使用prose类(Tailwind prose插件),内容量巨大时,prose的全局样式会导致大量DOM元素重排重绘,尤其每次编辑触发内容更新时。

  • 优化方案:简化prose样式,移除不必要的全局规则;或自定义编辑器基础样式,避免使用过于复杂的全局样式集合。

4. Tiptap历史记录缓存过载

History扩展默认缓存所有编辑操作,内容超3000字时,历史记录内存占用显著增加,每次编辑都会触发序列化/反序列化,阻塞主线程。

  • 优化方案:配置History扩展的depth参数,限制历史记录最大条数:
History.configure({
  depth: 20 // 仅保留最近20次操作记录
})

5. 组件不必要重渲染

虽移除部分useState相关组件,但仍可能存在其他组件在编辑器内容变化时频繁重渲染,比如父组件未用React.memo包裹,或依赖项处理不当。

  • 排查方向:用React DevTools的Profiler工具,查看编辑时频繁重渲染的组件;确认useEditor的配置参数稳定(当前editorExtensions为导出常量,无问题,若动态生成需用useMemo包裹)。
  • 优化方案:用React.memo包裹编辑器父组件及相关子组件;确保useEditor配置参数稳定。

6. 大内容初始渲染开销

若初始加载的data?.content本身超3000字,Tiptap解析渲染时会消耗大量主线程资源,导致页面冻结。

  • 优化方案:对大内容做懒加载,先渲染部分内容,剩余内容在编辑器初始化后异步插入;或用editor.commands.insertContent分批插入内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:34:55