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

使用Formik控制react-draft-wysiwyg编辑器时光标定位异常问题

我明白你遇到的这个光标跳转问题了,这其实是因为你每次渲染编辑器时都从HTML字符串重新创建了EditorState,导致编辑器丢失了光标位置、选区这类关键状态。咱们来一步步解决它:

问题根源分析

你当前的写法是在render函数里直接用setEditorState(this.props.field.value)生成EditorState传给组件,这意味着每次组件渲染(哪怕只是输入一个字符),都会生成一个全新的EditorState实例。react-draft-wysiwyg会把这个全新的状态当作完全新的内容,自然会把光标重置到内容开头,就出现了你看到的“从右往左输入”的异常效果。

解决方案:本地维护编辑器状态,仅在Formik值变化时同步

核心思路是让组件内部维护EditorState的本地状态,只在Formik的字段值真正变化时(比如初始化、表单重置),才从HTML字符串同步编辑器状态;而编辑器自身的输入变化,先更新本地状态,再同步HTML到Formik。这样既能保留Formik控制表单状态的优势,又能让编辑器正常维护光标、选区等交互状态。

修改后的组件代码

import React from 'react';
import { Editor } from 'react-draft-wysiwyg';
import { convertFromHTML, EditorState, ContentState } from 'draft-js';
import { stateToHTML } from 'draft-js-export-html';

class XXX extends React.Component {
  // 组件内部维护编辑器状态
  state = {
    editorState: EditorState.createEmpty()
  };

  componentDidMount() {
    // 初始化时从Formik的初始值加载编辑器状态
    this.syncEditorStateFromFormik(this.props.field.value);
  }

  componentDidUpdate(prevProps) {
    // 仅当Formik的字段值发生变化时(比如表单重置),才同步编辑器状态
    if (prevProps.field.value !== this.props.field.value) {
      this.syncEditorStateFromFormik(this.props.field.value);
    }
  }

  // 从Formik的HTML字符串同步到编辑器状态的工具方法
  syncEditorStateFromFormik = (html) => {
    if (!html) {
      this.setState({ editorState: EditorState.createEmpty() });
      return;
    }
    const blocksFromHTML = convertFromHTML(html);
    if (blocksFromHTML.contentBlocks) {
      const contentState = ContentState.createFromBlockArray(
        blocksFromHTML.contentBlocks,
        blocksFromHTML.entityMap
      );
      this.setState({ editorState: EditorState.createWithContent(contentState) });
    } else {
      this.setState({ editorState: EditorState.createEmpty() });
    }
  };

  onEditorStateChange = (editorState) => {
    // 先更新本地状态,保留光标、选区等交互状态
    this.setState({ editorState });
    // 再把编辑器内容转为HTML同步到Formik
    const contentState = editorState.getCurrentContent();
    this.props.form.setFieldValue(this.props.field.name, stateToHTML(contentState));
  };

  render() {
    return (
      <Editor
        editorState={this.state.editorState}
        onEditorStateChange={this.onEditorStateChange}
        // 这里保留你原来的其他编辑器配置项...
      />
    );
  }
}

关键改动说明

  1. 本地状态维护:用组件自身的state保存editorState,确保编辑器能持续跟踪光标、选区、撤销历史等状态。
  2. 按需同步Formik值:只在组件初始化或Formik字段值真正变化时,才从HTML字符串生成新的EditorState,避免不必要的状态重置。
  3. 先更新本地再同步Formik:编辑器内容变化时,先更新本地状态保证交互正常,再同步HTML到Formik,兼顾表单状态控制和编辑器体验。

这样修改后,你既能继续使用Formik的表单重置、验证等功能,编辑器的输入交互也会完全正常,不会再出现光标跳转到开头的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:31:11