React中按下Enter键传递Lexical编辑器文本内容的问题
问题描述
使用Lexical编辑器时,点击提交按钮能正常传递编辑器文本内容,但按下Enter键提交时返回空字符串。当前实现逻辑是通过TextContentListener监听编辑器内容变化,将值同步到useState的textValue中,计划在Enter键触发时传递该值。
问题原因
- React状态更新异步性:
setTextValue是异步操作,Enter键触发时可能还未完成状态更新,导致拿到旧值。 - 闭包捕获旧值:
EnterCommand中注册的KEY_ENTER_COMMAND命令,其回调里的onSubmit是组件初始化时捕获的旧值,后续textValue更新后,该回调并未重新注册,仍使用旧的textValue。 - 清空命令时序问题:调用
onSubmit()后立刻执行CLEAR_EDITOR_COMMAND,会触发TextContentListener将textValue设为空,进一步加剧状态不同步。
解决方案
方案1:直接从编辑器获取文本(推荐)
绕过React状态,直接在Enter事件中从Lexical编辑器实例获取当前文本,避免状态同步问题。
修改EnterCommand组件:
const EnterCommand = ({ onSubmit = () => {} }) => { const [editor] = useLexicalComposerContext(); useEffect(() => { return editor.registerCommand( KEY_ENTER_COMMAND, enterEvent, COMMAND_PRIORITY_HIGH ); }, [editor, onSubmit]); // 添加onSubmit到依赖,确保回调更新 const enterEvent = (event) => { const { shiftKey, key } = event; if (key === "Enter" && !shiftKey) { event.preventDefault(); // 直接从编辑器获取当前文本 const currentText = editor.getTextContent(); onSubmit(currentText); editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined); } return true; }; return null; };
修改Editor组件调用:
// 移除textValue相关状态同步逻辑,直接传递submit函数 <EnterCommand onSubmit={submit} /> // 按钮也可统一用编辑器直接获取文本 <SubmitButton onSubmit={() => submit(editor.getTextContent())} />
方案2:修复闭包捕获问题
让EnterCommand在onSubmit变化时重新注册命令,确保捕获最新的textValue。
修改EnterCommand组件:
const EnterCommand = ({ onSubmit = () => {} }) => { const [editor] = useLexicalComposerContext(); useEffect(() => { return editor.registerCommand( KEY_ENTER_COMMAND, enterEvent, COMMAND_PRIORITY_HIGH ); }, [editor, onSubmit]); // 添加onSubmit到依赖数组 const enterEvent = (event) => { const { shiftKey, key } = event; if (key === "Enter" && !shiftKey) { event.preventDefault(); onSubmit(); editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined); } return true; }; return null; };
在Editor组件中用useCallback包裹提交回调:
const submitHandler = useCallback(() => { submit(textValue); }, [submit, textValue]); <EnterCommand onSubmit={submitHandler} />
方案3:使用Ref保存最新值
通过useRef保存最新的textValue,避免闭包捕获旧值。
修改Editor组件:
export default function Editor({ submit = () => {} }) { const [textValue, setTextValue] = useState(""); const textValueRef = useRef(""); const placeholderRef = useRef(null); // 同步textValue到ref useEffect(() => { textValueRef.current = textValue; }, [textValue]); const initialConfig = { namespace: "MyEditor", theme, onError, }; return ( <div className="grow pl-2 flex items-end gap-2"> <div className="bg-gray-200/80 pl-4 p-2 rounded-3xl grow mr-12"> <div> <div className="relative"> <LexicalComposer initialConfig={initialConfig}> {/* 其他插件保持不变 */} <TextContentListener onChange={(text) => { setTextValue(text.trim() === "" ? "" : text); }} /> <EnterCommand onSubmit={() => submit(textValueRef.current)} /> <SubmitButton onSubmit={() => submit(textValue)} /> </LexicalComposer> </div> </div> </div> </div> ); }
内容的提问来源于stack exchange,提问作者LVC
相关产品推荐
相关产品推荐

