React组件修改DOM后强制重渲染及Prism.js语法高亮异常问题
解决React中Prism.js props变化后高亮异常的问题
这个问题我之前也碰到过,本质是React的DOM更新机制和Prism的高亮标记冲突了——当父组件的输入项改变导致代码内容更新时,React只是增量更新了<code>元素的内容,但Prism之前给这个元素添加的高亮<span>标签还残留在DOM里,新旧内容混在一起就会出现高亮异常。下面给你两个靠谱的解决方案:
方案1:用key属性强制组件重新挂载
这是最简单直接的方法。React会根据key来判断组件是否需要重新创建,当key值变化时,React会卸载旧组件并挂载新组件,这样Prism就能在全新的DOM元素上重新执行高亮,完全避免旧高亮标记的干扰。
在父组件中使用你的代码组件时,把key绑定到代码内容(或者唯一标识代码的变量):
// 父组件中的用法 <CodeExample code={currentGeneratedCode} language="javascript" key={currentGeneratedCode} // 代码内容变化时,key跟着变 />
对应的代码组件(类组件示例):
class CodeExample extends React.Component { constructor(props) { super(props); this.codeRef = React.createRef(); } componentDidMount() { // 组件挂载时执行高亮 Prism.highlightElement(this.codeRef.current); } render() { return ( <pre> <code ref={this.codeRef} className={`language-${this.props.language}`} > {this.props.code} </code> </pre> ); } }
方案2:在componentDidUpdate中重新处理高亮(适合不想重新挂载组件的场景)
如果不想通过重新挂载组件解决,可以在componentDidUpdate中先清除旧的高亮标记,再重新执行高亮。核心是确保<code>元素内的内容是最新的原始代码,再让Prism重新处理:
class CodeExample extends React.Component { constructor(props) { super(props); this.codeRef = React.createRef(); } componentDidMount() { this.highlightCode(); } componentDidUpdate(prevProps) { // 只有当代码内容变化时才重新高亮 if (prevProps.code !== this.props.code) { this.highlightCode(); } } highlightCode() { const codeElement = this.codeRef.current; if (!codeElement) return; // 先把元素内容还原为原始代码,清除旧的高亮标记 codeElement.innerHTML = this.props.code; // 重新执行高亮 Prism.highlightElement(codeElement); } render() { return ( <pre> <code ref={this.codeRef} className={`language-${this.props.language}`} > {this.props.code} </code> </pre> ); } }
如果是用函数组件+Hook,写法类似:
import { useRef, useEffect } from 'react'; function CodeExample({ code, language }) { const codeRef = useRef(null); useEffect(() => { const highlight = () => { if (!codeRef.current) return; codeRef.current.innerHTML = code; Prism.highlightElement(codeRef.current); }; highlight(); }, [code, language]); // 依赖代码内容和语言,变化时重新执行 return ( <pre> <code ref={codeRef} className={`language-${language}`} > {code} </code> </pre> ); }
为什么之前的写法有问题?
你之前在componentDidUpdate中只调用了Prism.highlightElement(),但此时<code>元素里还保留着Prism之前生成的高亮标签,React的增量更新只是把新代码插入到这些旧标签中,导致Prism无法正确识别原始代码结构,自然会出现高亮异常。上面的两种方法要么彻底重建组件,要么先清除旧高亮再重新处理,都能解决这个问题。
内容的提问来源于stack exchange,提问作者Hartator
相关产品推荐
相关产品推荐

