React中@toast-ui/react-editor Viewer如何传异步initialValue
核心问题原因
@toast-ui/react-editor 导出的 Viewer 组件,其 initialValue 是仅在首次挂载时生效的初始化配置,后续即使传入组件的 initialValue prop 发生变化,已经生成的Viewer实例不会自动同步更新内容。
当前代码的执行时序刚好触发了这个特性:
- 组件首次渲染时,异步课程详情接口还未返回结果,此时
Classs.content为undefined,Viewer已经带着空的初始值完成挂载 - 接口返回后,
setClasss更新状态,哪怕传给Viewer的initialValue已经是有效内容,已经挂载完成的Viewer不会响应这个prop变化,最终表现为内容不渲染 - 页面上的隐藏textarea是原生受控组件,会直接跟随状态值更新,所以能正常读到有效内容,和Viewer的表现形成明显反差
可落地的解决方案
方案1:待异步数据就绪后再挂载Viewer组件(最推荐)
从挂载时机上避免空值初始化的问题,等Classs.content拿到有效值后再渲染Viewer组件,初始化时就能传入正确的内容,完全匹配组件的设计逻辑。
修改后的核心代码如下:
// 移除提前定义asdasd变量的逻辑,在页面渲染逻辑中加状态判断 return ( <div style={{ width: '100%', padding: '3rem 4rem' }}> <div> {/* 隐藏的测试textarea可保留用于调试 */} <textarea value={Classs.content} readOnly style={{ display: "none" }}></textarea> <div> {/* 仅当content有有效值时才渲染Viewer */} {Classs.content ? ( <Viewer ref={editorRef} height="500px" initialValue={Classs.content} /> ) : ( <div style={{ height: "500px", display: "flex", alignItems: "center", justifyContent: "center", color: "#999" }}> 内容加载中... </div> )} </div> <Row gutter={[16, 16]}> <Col lg={18} sm={24}></Col> <Col lg={6} sm={24}> <ProductInfo detail={Classs} /> </Col> </Row> </div> </div> )
冗余代码修正
原代码中给Viewer传入的viewer="true"属性属于多余配置:当前导入的是只读的Viewer组件本身,不需要额外通过该属性开启只读模式,冗余传参可能触发组件prop校验警告,直接删除即可。
方案2:通过ref手动同步内容(需提前挂载场景)
如果业务要求必须在数据未返回时就完成Viewer组件挂载,可以通过ref绑定组件实例,在异步数据拿到后手动调用实例方法更新内容。
核心修改逻辑:
- 给Viewer组件绑定已经定义好的
editorRef - 在接口返回数据的回调中,拿到Viewer实例后调用
setMarkdown方法写入内容
对应代码片段:
useEffect(() => { dispatch(videoclassdetail(classId)) .then((res) => { const courseData = res.payload setClasss(courseData) // 数据存在时,通过ref拿到实例手动更新内容 if (courseData?.content && editorRef.current) { const viewerInstance = editorRef.current.getInstance() viewerInstance.setMarkdown(courseData.content) } }) }, [dispatch, classId])
注意事项
- 调用
getInstance()前必须判断ref是否已经绑定完成,避免组件未挂载时触发空指针报错 - 不要在组件首次渲染的同步逻辑中直接调用实例方法,此时ref还未完成绑定
内容的提问来源于stack exchange,提问作者nojeong
相关产品推荐
相关产品推荐

