ReactJS Lexical编辑器因初始值重渲染失焦问题求助
问题分析与解决方案
问题根源
- 组件频繁重建导致失焦:每次输入字符时,
onChange会更新Context中的insights,触发currentSavedInsightText变化,而它在useMemo依赖中,会导致TextEditor被重新创建(卸载再挂载),直接丢失焦点。 - 编辑器状态被强制重置:
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
相关产品推荐
相关产品推荐

