Reputation: 51
Question Desp: How could I highlight a custom syntax with prismjs in a react project?
I've created an extending syntax file (let's call it newlang
) by following the guide.
And I know in prismjs there are three ways to highlight code:
highlightElement()
highlightAll()
highlight()
First, I tried to require my custom syntax file in my app.
import 'utils/highlight/prism-newlang';
Then, in my highlighting component,
highlightElement()
: ❌CANNOT get my code highlightingimport Prism from 'prismjs';
function CodeHighlight({ value, language }) {
const codeEle = useRef(null);
useEffect(() => {
Prism.highlightElement(codeEle.current, false);
}, []);
return (
<pre className={`language-${language}`}>
<code ref={codeEle} className={`language-${language}`}>
{value}
</code>
</pre>
);
}
highlightAll()
: ❌CANNOT get my code highlightinghighlight()
: ✅CAN get my code highlightingimport { highlight, languages } from 'prismjs/components/prism-core';
function CodeHighlight({ value, language }) {
const codeNode = useRef(null);
useEffect(() => {
const code = codeNode.current.textContent;
const highlightHTML = highlightCode(code, language);
codeNode.current.innerHTML = highlightHTML;
});
return (
<pre className={`language-${language}`}>
<code ref={codeNode} className={`language-${language}`}>
{value}
</code>
</pre>
);
}
I wonder what's the problem of Method 1 & 2. (Will be the matter of the loading order of custom syntax file?)
Upvotes: 3
Views: 3160
Reputation: 61
For those who run into this issue in the future, I was able to get the first method working. In my case, I was calling Prism.highlight
in the handleChange which was calling the function before the DOM was even updated with the internalText
. I now use the useEffect
hook which is invoked after the DOM is rendered, the trick is you need to declare the internalText
as a subscribed parameter.
I have attached my Typescript component.
Hope this helps.
import React, { useState, ChangeEvent, useRef, useEffect } from 'react'
import './prism.css'
import Prism from "prismjs";
export function CodeBlockTile() {
const language = "javascript"
const codeElement = useRef<HTMLElement | null>(null);
const [internalText, setInternalText] = useState<string>("")
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
setInternalText(event.target.value);
};
useEffect(() => {
if (codeElement.current) {
Prism.highlightElement(codeElement.current)
}
}, [internalText])
return (
<div>
<textarea onChange={handleChange} value={internalText}>
</textarea>
<pre>
<code ref={codeElement} className={`language-${language}`}>
{internalText}
</code>
</pre>
</div>
)
}
Upvotes: 3