ReactDOMServer渲染react-mathjax组件为字符串返回空问题求解
问题诱因
你使用的react-mathjax库原生不支持服务端渲染逻辑,它的核心渲染流程完全依赖客户端环境:
MathJax.Provider会在客户端组件挂载后才异步加载MathJax核心脚本,初始化全局MathJax实例MathJax.Node组件只会在客户端接收到MathJax初始化完成的信号后,才会解析传入的公式生成对应的DOM节点
而ReactDOMServer.renderToString/renderToStaticMarkup是同步执行的逻辑,运行时MathJax还没完成初始化,MathJax.Node组件没有可以输出的DOM结构,所以转换后的字符串对应位置会是空值,外层包裹的原生HTML标签不受影响可以正常输出。
解决方案
方案1:更换支持SSR的数学公式渲染库
可以替换为better-react-mathjax、react-mathjax2这类兼容服务端渲染的库,这类库会在服务端渲染阶段生成公式占位结构,客户端加载完成后自动补全渲染,可直接被ReactDOMServer正确转换为字符串。方案2:手动构造公式占位字符串
不需要通过组件生成公式,直接按照MathJax的语法规则构造HTML字符串,行内公式用\(公式内容\)包裹,块级公式用\[公式内容\]包裹,将构造好的字符串通过dangerouslySetInnerHTML注入后,在客户端调用MathJax的typeset方法触发公式渲染即可,示例代码:
// 构造带公式的HTML字符串 const html = ` <span> \(x=2\) <p>普通HTML内容</p> </span> `; // 客户端组件挂载后触发渲染 useEffect(() => { if (window.MathJax) { window.MathJax.typeset(); } }, []);
- 方案3:客户端侧获取渲染完成的HTML
如果必须保留现有Math组件的写法,可以在客户端等待MathJax渲染完成后,通过DOM节点的innerHTML属性拿到渲染好的HTML字符串,示例代码:
import { useRef, useEffect, useState } from 'react'; import MathJax from "react-mathjax"; const Math = () => ( <MathJax.Provider> <MathJax.Node inline formula="x=2" /> </MathJax.Provider> ); export default function App() { const mathRef = useRef(null); const [renderedHtml, setRenderedHtml] = useState(''); useEffect(() => { // 监听MathJax加载完成事件,也可以用setTimeout做延迟兜底 const checkMathJax = setInterval(() => { if (window.MathJax?.version && mathRef.current?.children.length) { setRenderedHtml(mathRef.current.innerHTML); clearInterval(checkMathJax); } }, 100); return () => clearInterval(checkMathJax); }, []); return ( <> {/* 隐藏的占位节点,用于渲染后获取HTML */} <div ref={mathRef} style={{ display: 'none' }}> <Math /> </div> {/* 用拿到的HTML字符串渲染 */} <div dangerouslySetInnerHTML={{ __html: renderedHtml }} /> </> ); }
内容的提问来源于stack exchange,提问作者Dyarlen Iber
相关产品推荐
相关产品推荐

