Using MathJax with React
Published on 4 June 2020This post describes how to use React (Typescript) and MathJax.
There are a few performance optimizations:
- React.memo makes it so that even if the parent rerenders but the Latex does not change, the component does not rerender (reference).
- The MathJax
typeset()
is only called whenrawLatex
changes. Technically, this is unnecessary, as theReact.memo
should mean that it only rerenders when the prop changes.
You can either load MathJax in the head or load it dynamically in other ways.
With Next.js, I was running into issues with using the <Head>
tag; see how to
dynamically load scripts in React.
/**
* Combined with dynamic script loading, this component allows us to render
* MathJax. Uses MathJax 3.0. It takes an approach similar to the article below:
*
* https://engineering.classpro.in/render-latex-in-react-using-mathjax-f9742504678
*
* but then adapts based on MathJax 3.0:
*
* http://docs.mathjax.org/en/latest/web/typeset.html#handling-asynchronous-typesetting
*/
import React from 'react';
const getMathJax = () => (window as any).MathJax;
const typeset = (selector: () => HTMLElement) => {
const mathJax = getMathJax();
// If MathJax script hasn't been loaded yet, then do nothing.
if (!mathJax) {
return null;
}
mathJax.startup.promise = mathJax.startup.promise
.then(() => {
selector();
return mathJax.typesetPromise();
})
.catch((err: any) => console.error(`Typeset failed: ${err.message}`));
return mathJax.startup.promise;
};
interface LatexProps {
rawLatex: string;
}
const Latex: React.FC<LatexProps> = ({ rawLatex }) => {
const ref = React.createRef<HTMLSpanElement>();
React.useEffect(() => {
typeset(() => ref.current!);
}, [rawLatex]);
return <span ref={ref}>{rawLatex}</span>;
};
export default React.memo(Latex);