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

ReactJS Lexical编辑器因初始值重渲染失焦问题求助

问题分析与解决方案

问题根源

  1. 组件频繁重建导致失焦:每次输入字符时,onChange会更新Context中的insights,触发currentSavedInsightText变化,而它在useMemo依赖中,会导致TextEditor被重新创建(卸载再挂载),直接丢失焦点。
  2. 编辑器状态被强制重置:TextEditor中的TextEditorInitialValue组件,每次initialValue变化就调用editor.setEditorState,相当于强制覆盖编辑器内部状态,不仅干扰焦点,还会打断输入流程。

分步解决方案

1. 修复TextEditor的初始值逻辑,避免强制重置状态

修改TextEditorInitialValue,只在外部状态真正变化(而非用户输入触发的内部同步)时更新编辑器状态,同时避免污染全局配置:

import { useRef } from "react"; // 新增引入

// ... 其他代码不变 ...

function TextEditorInitialValue({ value = null }) {
  const [editor] = useLexicalComposerContext();
  const lastExternalValueRef = useRef(value); // 记录上次外部传入的值

  useEffect(() => {
    if (value === null) return;
    // 仅当外部值与上次记录值不同时,才更新编辑器状态
    if (value !== lastExternalValueRef.current) {
      const initialEditorState = editor.parseEditorState(
        value === "" ? emptyEditor : value
      );
      editor.setEditorState(initialEditorState);
      lastExternalValueRef.current = value;
    }
  }, [editor, value]);

  return null;
}

// 修改TextEditor组件,避免修改全局editorConfig
export default React.memo(function TextEditor({ editMode, onChange, initialValue }) {
  const localEditorConfig = useMemo(() => ({
    ...editorConfig,
    editable: editMode,
    ...(initialValue ? { editorState: initialValue } : {}),
  }), [editMode, initialValue]);

  return (
    <LexicalComposer initialConfig={localEditorConfig}>
      <div className="editor-container">
        {editMode && <ToolbarPlugin />}
        <div className="editor-inner">
          <RichTextPlugin
            contentEditable={<ContentEditable className="editor-input" />}
            placeholder={<Placeholder />}
            ErrorBoundary={LexicalErrorBoundary}
            editorState={initialValue}
          />
          <OnChangePlugin onChange={onChange} />
          <HistoryPlugin />
          <AutoFocusPlugin />
          <CodeHighlightPlugin />
          <ListPlugin />
          <LinkPlugin />
          <AutoLinkPlugin />
          <ListMaxIndentLevelPlugin maxDepth={7} />
          <MarkdownShortcutPlugin transformers={TRANSFORMERS} />
        </div>
      </div>
      <TextEditorEditable editable={editMode} />
      <TextEditorInitialValue value={initialValue} />
    </LexicalComposer>
  );
});

2. 优化Insight组件的渲染逻辑,避免不必要的重建

去掉冗余的useMemo,改用React.memo优化组件渲染,同时调整onChange的依赖逻辑:

import React, { useCallback, useEffect, useMemo } from "react"; // 修正react大写

// ... 其他代码不变 ...

function Insight({ insightName }) {
  const { insights, setInsights, editMode, activeAssessment } = useAssessmentContext();
  useApiData();
  
  const currentSavedInsightText = insights[insightName];

  const onChange = useCallback(
    (value) => {
      const newValue = JSON.stringify(value);
      // 直接对比新值与当前Context值,避免不必要的更新
      if (newValue === currentSavedInsightText) return;
      setInsights((prev) => ({ ...prev, [insightName]: newValue }));
    },
    [insightName, setInsights, currentSavedInsightText]
  );

  // 移除useMemo,依赖React.memo优化TextEditor本身的渲染
  return (
    <TextEditor
      onChange={onChange}
      editMode={editMode}
      initialValue={currentSavedInsightText}
    />
  );
}

export default React.memo(Insight);

效果说明

  • 输入时不再丢失焦点:TextEditor不会被频繁重建,编辑器内部状态稳定。
  • 双向实时同步:当一个编辑器输入内容时,Context更新会触发另一个编辑器通过TextEditorInitialValue同步状态,实现类似普通input的双向绑定效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:52:57