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

React Quill编辑器输入异常:光标错位、退格失效求助

React Quill光标跳转、退格异常问题修复

问题原因

你的QuillEditor组件同时维护了内部状态editorHtml和接收父组件传入的value,导致编辑器出现状态冲突:每次输入时,子组件先更新自身state,再通知父组件更新editorContent,父组件又把新值传回子组件,触发编辑器重新渲染,光标位置因此丢失、出现跳转;退格异常也是因为重复渲染打断了编辑器的正常事件处理。

修复步骤

1. 移除QuillEditor内部的冗余状态

删除组件内的editorHtml状态,直接以父组件传入的value作为编辑器的唯一数据源,避免双向状态冲突。

2. 简化编辑器内容变更逻辑

直接在handleChange中调用父组件的onEditorChange,不需要先更新自身state。

修改后的QuillEditor.js代码

import React from 'react';
import ReactQuill, { Quill } from 'react-quill';
import "react-quill/dist/quill.snow.css";
import ImageResize from "quill-image-resize-module-react";

const __ISMSIE__ = navigator.userAgent.match(/Trident/i) ? true : false;

var icons = Quill.import("ui/icons");
Quill.register("modules/imageResize", ImageResize);
icons["undo"] = `<svg viewbox="0 0 18 18">
    <polygon class="ql-fill ql-stroke" points="6 10 4 12 2 10 6 10"></polygon>
    <path class="ql-stroke" d="M8.09,13.91A4.6,4.6,0,0,0,9,14,5,5,0,1,0,4,9"></path>
  </svg>`;
icons["redo"] = `<svg viewbox="0 0 18 18">
    <polygon class="ql-fill ql-stroke" points="12 10 14 12 16 10 12 10"></polygon>
    <path class="ql-stroke" d="M9.91,13.91A4.6,4.6,0,0,1,9,14a5,5,0,1,1,5-5"></path>
  </svg>`;

class QuillEditor extends React.Component {
    _isMounted;
    reactQuillRef = null;

    constructor(props) {
        super(props);
    }

    componentDidMount() {
        this._isMounted = true;
    }

    componentWillUnmount() {
        this._isMounted = false;
    }

    handleChange = (html) => {
        // 直接通知父组件更新,不再维护内部状态
        this.props.onEditorChange(html);
    };

    undoHandler = () => {
        this.reactQuillRef.editor.history.undo("undo");
    };
    
    redoHandler = () => {
        this.reactQuillRef.editor.history.redo("redo");
    };

    // 补充modules定义(原代码缺失,避免功能异常)
    modules = {
        imageResize: {
            parchment: Quill.import('parchment'),
            modules: ['Resize', 'DisplaySize']
        },
        toolbar: [
            ['bold', 'italic', 'underline', 'strike'],
            ['blockquote', 'code-block'],
            [{ 'header': 1 }, { 'header': 2 }],
            [{ 'list': 'ordered'}, { 'list': 'bullet' }],
            [{ 'color': [] }, { 'background': [] }],
            ['link', 'image'],
            ['undo', 'redo']
        ]
    };

    render() {
        return (
            <div>
                <ReactQuill
                    style={{height: '500px', padding: '0px', width: '100%',  maxWidth: '1150px' }}
                    ref={(el) => { this.reactQuillRef = el }}
                    theme={'snow'}
                    onChange={this.handleChange}
                    modules={this.modules}
                    value={this.props.value || (__ISMSIE__ ? "<p>&nbsp;</p>" : "")}
                    placeholder={this.props.placeholder}
                />
            </div>
        )
    }
}

export default QuillEditor;

3. 优化父组件PostInfo.jsx的逻辑

确保onEditorChange直接更新状态,避免多余的中间处理:

// 简化onEditorChange
const onEditorChange = (value) => {
  console.log("onEditorChange called");
  setEditorContent(value);
};

// 渲染QuillEditor时简化回调
<QuillEditor
  value={editorContent}
  onEditorChange={onEditorChange}
/>

额外注意事项

  • 确保父组件的editorContent初始化和更新不会触发不必要的重渲染,比如避免在useEffect中重复设置相同的值。
  • 如果编辑器仍有异常,检查是否有其他组件逻辑导致PostInfo组件频繁重渲染,可以用React.memo包裹QuillEditor组件,减少不必要的重渲染:
export default React.memo(QuillEditor);

内容的提问来源于stack exchange,提问作者sultan.h

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:22:45