NextJS14中ReactQuill v2.0.0焦点跳失问题求助(DOMNodeInserted弃用)
问题描述
在NextJS 14应用中使用react-quill 2.0.0包,此前运行正常。近期撰写新文章时,输入框焦点会自动跳转到页面顶部,脱离<ReactQuill/>组件,同时控制台出现弃用警告:
[Deprecation] Listener added for a 'DOMNodeInserted' mutation event. Support for this event type has been removed, and this event will no longer be fired.
经排查,该问题源于ReactQuill 2.0.0使用了已被Chrome移除支持的DOMNodeInserted事件。
当前实现代码
"use client" import React, { useState } from 'react'; import dynamic from 'next/dynamic'; import 'react-quill/dist/quill.snow.css'; import axios from 'axios'; const NewPostPage = () => { const [content, setContent] = useState<string>(''); const ReactQuill = dynamic(() => import('react-quill'), { ssr: false }); const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); const formData = new FormData(event.currentTarget); const title = formData.get('title') as string; const author = formData.get('author') as string; try { const response = await axios.post('/api/posts/create', { title, author, content, }); if (response.status === 200) { alert('Post created successfully!'); window.location.href = '/'; } } catch (error: any) { throw new Error('Error creating post:', error); } }; return ( <> <div className="p-4"> <h1 className="text-3xl font-bold mb-2">Creating New Blog Post</h1> <hr className="mb-6"/> </div> <form onSubmit={handleSubmit}> <div className="p-4"> <label htmlFor="author" className="text-gray-200 font-bold pb-4">Blog Post Title</label> <br/><br/> <input type="text" name="title" id="title" placeholder="Blog Post Title" className="w-full mb-4 p-3 bg-black" autoFocus={true} required /> </div> <div className="p-4"> <label htmlFor="author" className="text-gray-200 font-bold pb-4">Author Name</label> <br/><br/> <input type="text" name="author" id="author" placeholder="Author Name" className="w-full mb-4 p-3 bg-black" required /> </div> <div className="p-4"> <label htmlFor="content" className="text-gray-200 font-bold">Blog Content</label> <br/><br/> <ReactQuill theme="snow" value={content} onChange={setContent} style={{ height: '33vh', marginBottom: '40px', color: 'white' }} /> </div> <div className="p-4"> <button type="submit" className="border border-white px-4 py-2 rounded-md hover:bg-slate-900">Create Post</button> </div> </form> </> ); }; export default NewPostPage;
解决方案
1. 优先升级ReactQuill到最新版本
ReactQuill 2.0.0之后的版本已经将DOMNodeInserted替换为现代浏览器支持的MutationObserver,彻底解决该问题。执行升级命令:
npm update react-quill # 或使用yarn yarn upgrade react-quill
2. 优化动态导入位置
当前代码将ReactQuill的动态导入放在组件内部,可能导致每次组件渲染时重新初始化,加剧焦点异常。将动态导入移至组件外部:
"use client" import React, { useState } from 'react'; import dynamic from 'next/dynamic'; import 'react-quill/dist/quill.snow.css'; import axios from 'axios'; // 移至组件外部,确保只初始化一次 const ReactQuill = dynamic(() => import('react-quill'), { ssr: false }); const NewPostPage = () => { // 原有逻辑保持不变 }; export default NewPostPage;
3. 临时禁用旧事件监听(不推荐长期使用)
若暂时无法升级,可通过Quill的初始化钩子手动移除DOMNodeInserted事件监听:
<ReactQuill theme="snow" value={content} onChange={setContent} style={{ height: '33vh', marginBottom: '40px', color: 'white' }} modules={{ // 保留原有工具栏配置 toolbar: ['bold', 'italic', 'underline', 'link'], editor: { init: (quill) => { // 遍历编辑器相关元素,移除DOMNodeInserted监听 const targetElements = [quill.root, ...Array.from(quill.root.querySelectorAll('*'))]; targetElements.forEach(el => { const listeners = getEventListeners(el).DOMNodeInserted; if (listeners) { listeners.forEach(({ listener }) => { el.removeEventListener('DOMNodeInserted', listener); }); } }); } } }} />
注意:该方案依赖浏览器非标准的getEventListeners API,仅适合临时调试,生产环境请优先升级版本。
4. 排查NextJS Strict Mode影响
NextJS 14的Strict Mode会触发两次组件渲染,可能导致组件初始化异常。若问题仍存在,可暂时关闭Strict Mode(不推荐长期),或确保组件逻辑在Strict Mode下稳定运行。
内容的提问来源于stack exchange,提问作者Devon Kiss

