Next.js项目引入GrapesJS遇TypeError: Cannot read properties of null错误
在Next.js中集成GrapesJS时出现
TypeError: Cannot read properties of null (reading 'querySelector')的解决方案 问题背景
在Next.js项目中引入GrapesJS编辑器时触发错误:TypeError: Cannot read properties of null (reading 'querySelector'),推测原因是GrapesJS初始化时需要定位#gjs容器,但此时DOM尚未完成渲染,无法找到对应元素。
现有代码
Editor.js组件代码
import React, { useEffect, useState } from "react"; import grapesjs from "grapesjs"; const Editor = () => { const [editor, setEditor] = useState(null); useEffect(() => { const editor = grapesjs.init({ container: "#gjs", }); setEditor(editor); }, []); return ( <> <div id="gjs"></div> </> ); }; export default Editor;
/editor路由页面代码
import { getSession } from "next-auth/react"; import "../i18n/config/config"; import "grapesjs/dist/css/grapes.min.css"; import dynamic from "next/dynamic"; import Editor from "../features/Editor/components/Editor"; // const EditorComponent = dynamic( // () => import("../features/Editor/components/Editor"), // { // ssr: false, // } // ); export default function Home() { return <Editor />; } export async function getServerSideProps(context) { const session = await getSession(context); return { props: { session, }, }; }
已尝试但无效的方案
- 尝试动态导入Editor组件(禁用SSR),未生效
- 在页面中添加全局
<script src="//unpkg.com/grapesjs"></script>并移除组件内的import grapesjs from "grapesjs",项目可运行但控制台仍会出现该错误,对应页面代码如下:
import { getSession } from "next-auth/react"; import "../i18n/config/config"; import "grapesjs/dist/css/grapes.min.css"; import dynamic from "next/dynamic"; import Editor from "../features/Editor/components/Editor"; // const EditorComponent = dynamic( // () => import("../features/Editor/components/Editor"), // { // ssr: false, // } // ); export default function Home() { return ( <> <script src="//unpkg.com/grapesjs"></script> <Editor /> </> ); } export async function getServerSideProps(context) { const session = await getSession(context); return { props: { session, }, }; }
错误截图

解决方案
1. 修改Editor组件:使用Ref获取DOM节点而非ID选择器
避免依赖全局ID选择器,改用React的useRef直接获取DOM元素,同时确保仅在客户端环境初始化GrapesJS:
import React, { useEffect, useState, useRef } from "react"; import grapesjs from "grapesjs"; const Editor = () => { const [editor, setEditor] = useState(null); const gjsContainer = useRef(null); useEffect(() => { // 仅在客户端且DOM节点存在时初始化 if (typeof window !== 'undefined' && gjsContainer.current) { const editorInstance = grapesjs.init({ container: gjsContainer.current, }); setEditor(editorInstance); // 组件卸载时销毁编辑器,防止内存泄漏 return () => { editorInstance.destroy(); }; } }, []); return <div ref={gjsContainer} id="gjs"></div>; }; export default Editor;
2. 页面中正确启用动态导入(禁用SSR)
由于页面使用了getServerSideProps(服务端渲染),必须确保Editor组件仅在客户端渲染,因此需要移除直接导入,改用动态导入:
import { getSession } from "next-auth/react"; import "../i18n/config/config"; import "grapesjs/dist/css/grapes.min.css"; import dynamic from "next/dynamic"; // 动态导入Editor组件,禁用服务端渲染 const Editor = dynamic( () => import("../features/Editor/components/Editor"), { ssr: false, } ); export default function Home() { return <Editor />; } export async function getServerSideProps(context) { const session = await getSession(context); return { props: { session, }, }; }
方案说明
- 使用
useRef直接绑定DOM节点,避免了ID选择器在服务端渲染时找不到元素的问题 - 动态导入并禁用SSR,确保GrapesJS的初始化代码仅在浏览器环境执行
- 添加编辑器销毁的清理函数,避免内存泄漏
内容的提问来源于stack exchange,提问作者KarimHesham
相关产品推荐
相关产品推荐

