状态更新时Jsx-Parser内的MathJax无法重新渲染问题求助
问题描述
在React项目中,点击单选按钮触发状态更新时,所有DOM及JSX元素都会重新渲染,但Jsx-Parser组件内的MathJax元素除外;Jsx-Parser组件外的MathJax元素可随状态更新正常重渲染。已通过React开发者工具验证状态变化,即使将tex设为状态变量,该问题仍存在。
相关代码:
import { useState } from "react"; import MathJax from "react-mathjax"; import "./App.css"; import equations from "./equations/equations"; import JsxParser from "react-jsx-parser"; function App() { const { lhospital } = equations; const sample = { problem: `\\lim_{x\\rightarrow 1}\\frac{x^2-1}{x^2+3x-4}`, choices: [`1/5`, `2/5`, `3/5`, `4/5`], answer: `1/5`, solution: `Using <strong>L'Hospital's Rule </strong> {${lhospital}} </br>$\\lim_{x\\rightarrow 1}\\frac{x^2-1}{x^2+3x-4}=\\lim_{x\\rightarrow 1}\\frac{2x}{2x+3} =\\lim_{x\\rightarrow 1}\\frac{2(1)}{2(1)+3}=\\frac{2}{5}$`, }; const [choice, setChoice] = useState(0); // console.log(lhospital); const changeChoiceHandler = (event) => { setChoice(event.target.value); }; function submitHandler(event) { event.preventDefault(); console.log("submit"); } const tex = `<p>Differentiate </p><MathJax.Provider><MathJax.Node formula={problem} /></MathJax.Provider>`; return ( <MathJax.Provider> <JsxParser bindings={{ ...sample, }} components={{ MathJax }} jsx={tex} /> <form onSubmit={submitHandler}> <label> <input type="radio" value={sample.choices[0]} onChange={changeChoiceHandler} checked={choice === sample.choices[0]} /> {sample.choices[0]} </label> <label> <input type="radio" value={sample.choices[1]} onChange={changeChoiceHandler} checked={choice === sample.choices[1]} /> {sample.choices[1]} </label> <label> <input type="radio" value={sample.choices[2]} onChange={changeChoiceHandler} checked={choice === sample.choices[2]} /> {sample.choices[2]} </label> <label> <input type="radio" value={sample.choices[3]} onChange={changeChoiceHandler} checked={choice === sample.choices[3]} /> {sample.choices[3]} </label> <input type="submit" value="submit" /> </form> <MathJax.Node formula={`y=x`} /> </MathJax.Provider> ); } export default App;
原因分析
Jsx-Parser缓存机制:react-jsx-parser默认会缓存解析后的JSX结构,只要传入的jsx字符串未发生变化,它就不会重新解析渲染内部组件,导致MathJax元素无法触发更新。- MathJax.Provider嵌套冲突:你在
tex字符串里嵌套了MathJax.Provider,而外层已经存在全局的MathJax.Provider,这种嵌套会导致内部MathJax实例无法正确感知外层状态变化,进而无法触发重渲染。 - 绑定值的浅比较限制:虽然每次状态更新时
bindings都是新对象,但Jsx-Parser对bindings的浅比较可能判断其内容无变化,内部组件也就不会响应更新。
解决方案
方案1:用Key强制Jsx-Parser重渲染
给Jsx-Parser添加与状态choice绑定的key属性,状态变化时key改变,React会销毁旧组件实例并创建新的,从而强制重新解析JSX并渲染MathJax元素:
<JsxParser key={choice} bindings={{ ...sample, }} components={{ MathJax }} jsx={tex} />
方案2:移除内部的MathJax.Provider
外层已经有全局的MathJax.Provider,内部无需重复嵌套,修改tex字符串:
const tex = `<p>Differentiate </p><MathJax.Node formula={problem} />`;
方案3:让tex依赖状态动态更新
将tex设置为依赖状态的计算值,确保状态变化时tex内容更新,触发Jsx-Parser重新解析:
const tex = `<p>Differentiate (selected: ${choice}) </p><MathJax.Node formula={problem} />`;
方案4:手动触发MathJax刷新
利用Jsx-Parser的onRender钩子,在渲染完成后手动调用MathJax的排版方法:
<JsxParser bindings={{ ...sample, }} components={{ MathJax }} jsx={tex} onRender={() => { window.MathJax?.typeset(); }} />
内容的提问来源于stack exchange,提问作者joshuaebs
相关产品推荐
相关产品推荐

