无法将@uiw/react-codemirror组件值同步到useState状态
@uiw/react-codemirror 无法同步值到 useState 的问题解析与修复
问题根源
你的代码里onChange回调用了useCallback但依赖数组为空,这导致了闭包陷阱:
- 初始渲染时,
useCallback创建的onChange函数捕获了当时的value初始状态值。 - 后续每次调用
setValue(val)更新状态后,组件会重新渲染,但因为useCallback的依赖没有包含value,所以onChange函数的引用不会更新,内部始终保留着对初始value的闭包引用。 - 这就是为什么你在
onChange里console.log("value:", value)永远显示初始值——并非状态没更新,而是回调里的value是旧的闭包值。
另外,如果CodeMirror组件依赖onChange的引用变化来同步内部状态,还可能导致受控模式下的异常,进一步让你误以为状态没同步。
修复方案
方案1:修正useCallback的依赖数组
把value加入useCallback的依赖列表,这样每次value更新时,onChange都会生成新的函数,捕获最新的状态:
import React from "react"; import CodeMirror from '@uiw/react-codemirror'; import { javascript } from '@codemirror/lang-javascript'; export default function Test() { const [value, setValue] = React.useState("console.log('hello world!');"); const onChange = React.useCallback((val: string) => { setValue(val); console.log("val:", val); console.log("value:", value); // 下次触发时会显示最新状态 }, [value]); // 加入value依赖 return <CodeMirror value={value} height="200px" extensions={[javascript({ jsx: true })]} onChange={onChange} />; }
方案2:移除useCallback(简单直接)
如果不需要缓存onChange函数的引用,直接去掉useCallback,让每次渲染都生成新的回调函数,自然能捕获最新的value:
import React from "react"; import CodeMirror from '@uiw/react-codemirror'; import { javascript } from '@codemirror/lang-javascript'; export default function Test() { const [value, setValue] = React.useState("console.log('hello world!');"); const onChange = (val: string) => { setValue(val); console.log("val:", val); }; return <CodeMirror value={value} height="200px" extensions={[javascript({ jsx: true })]} onChange={onChange} />; }
针对Ctrl+S保存需求的优化
你不需要额外的codeText变量,直接使用value状态即可,逻辑更简洁:
import React from "react"; import CodeMirror from '@uiw/react-codemirror'; import { javascript } from '@codemirror/lang-javascript'; export default function Test() { const [value, setValue] = React.useState("console.log('hello world!');"); const onChange = (val: string) => { setValue(val); }; const handleSave = (ev: KeyboardEvent) => { if ((ev.ctrlKey || ev.metaKey) && ev.key === "s") { ev.preventDefault(); // 阻止浏览器默认保存行为 console.log("Code:", value); // 调用API发送value到后端 } }; React.useEffect(() => { window.addEventListener("keydown", handleSave); return () => { window.removeEventListener("keydown", handleSave); }; }, [value]); // 依赖value,确保保存时拿到最新状态 return <CodeMirror value={value} height="200px" extensions={[javascript({ jsx: true })]} onChange={onChange} />; }
内容的提问来源于stack exchange,提问作者star_huey
相关产品推荐
相关产品推荐

