Reputation: 48
I am trying to Render Math Equation in a React Component with MathJax. It actually worked well if I pre-render it within the HTML file, but it is a mess when i try rendering it in React.
Here's my code
class Latex extends React.Component {
constructor(props) {
super(props);
}
componentDidMount(){
MathJax.Hub.Queue(['Typeset', MathJax.Hub, ReactDOM.findDOMNode(this)]);
}
componentDidUpdate() {
MathJax.Hub.Queue(['Typeset', MathJax.Hub, ReactDOM.findDOMNode(this)]);
}
render() {
//dangerouslySetInnerHTML={{__html: this.props.children}}
return (
<h5 dangerouslySetInnerHTML={{__html: this.props.children}}></h5>
);
}
}
Math Display both in Regular HTML and React Element
Upvotes: 3
Views: 19831
Reputation: 46
Been a couple years, but if anyone is looking for a functional + mathjax3 based approach there is this repo:
https://github.com/jpribyl/react-hook-mathjax
demo of it is available at https://johnpribyl.com/react-hook-mathjax/
Usage is like this:
import React from "react";
import Tex2SVG from "react-hook-mathjax";
function App() {
return (
<div className="App">
<header className="App-header">
<Tex2SVG display="inline" latex="e^{i \pi} + 1 = 0" />
</header>
</div>
);
}
export default App;
import React from "react";
import Tex2SVG, { MathJaxProvider } from "react-hook-mathjax";
// This object contains the default options, more info at:
// http://docs.mathjax.org/en/latest/options/output/svg.html
const mathJaxOptions = {
svg: {
scale: 1, // global scaling factor for all expressions
minScale: .5, // smallest scaling factor to use
mtextInheritFont: false, // true to make mtext elements use surrounding font
merrorInheritFont: true, // true to make merror text use surrounding font
mathmlSpacing: false, // true for MathML spacing rules, false for TeX rules
skipAttributes: {}, // RFDa and other attributes NOT to copy to the output
exFactor: .5, // default size of ex in em units
displayAlign: 'center', // default for indentalign when set to 'auto'
displayIndent: '0', // default for indentshift when set to 'auto'
fontCache: 'local', // or 'global' or 'none'
localID: null, // ID to use for local font cache (for single equation processing)
internalSpeechTitles: true, // insert <title> tags with speech content
titleID: 0 // initial id number to use for aria-labeledby titles
}
}
function App() {
return (
<div>
<MathJaxProvider options={mathJaxOptions} />
<div className="App">
<header className="App-header">
<Tex2SVG display="inline" latex="e^{i \pi} + 1 = 0" />
</header>
</div>
</div>
);
}
export default App;
import React from "react";
import Tex2SVG from "react-hook-mathjax";
function App() {
const [inputValue, setInputValue] = React.useState(
"G_{\\mu\\nu} + \\Lambda g_{\\mu\\nu} = \\kappa T_{\\mu\\nu}",
);
return (
<div className="App">
<header className="App-header">
<h3>React Hook MathJax</h3>
<input
type="text"
defaultValue={inputValue}
onChange={e => setInputValue(e.target.value)}
/>
<div className="tex-container">
<Tex2SVG class="tex" tabindex={-1} latex={inputValue} />
</div>
</header>
</div>
);
}
export default App;
import React from "react";
import Tex2SVG from "react-hook-mathjax";
const getErrorFromHTML = (html) =>
html.children[1].firstChild.firstChild.attributes["data-mjx-error"].value;
function App() {
const [inputValue, setInputValue] = React.useState(
"G_{\\mu\\nu} + \\Lambda g_{\\mu\\nu} = \\kappa T_{\\mu\\nu}",
);
const [lastValidInput, setLastValidInput] = React.useState("");
const [error, setError] = React.useState(null);
const hasError = error !== null;
return (
<div className="App">
<header className="App-header">
<h3>React Hook MathJax</h3>
<input
className={`${hasError ? "error" : ""}`}
type="text"
defaultValue={inputValue}
onChange={e => {
setInputValue(e.target.value);
setError(null);
}}
/>
<div className="tex-container">
<Tex2SVG
class="tex"
tabindex={-1}
latex={hasError ? lastValidInput : inputValue}
onSuccess={() =>
setLastValidInput(hasError ? lastValidInput : inputValue)
}
onError={html => setError(getErrorFromHTML(html))}
/>
</div>
{hasError && <div>hint: {error}</div>}
</header>
</div>
);
}
export default App;
MathJaxProvider
props:options
Object, optionalTex2SVG
props:latex
string, requiredsvg
''
onSuccess
(HTMLElement) => void, optionalsvg
- it receives the html object generated by MathJax(html: HTMLElement) => {}
onError
(HTMLElement) => void, optionalsvg
- it receives the html object generated by MathJax(html: HTMLElement) => {}
Other html attributes
{[key: string]: any} optionalclass
- not className
etcUpvotes: 2
Reputation: 9
Add this before the Component class declare var MathJax;
. It should work seamlessly.
Upvotes: 0
Reputation: 1545
I used a combination of algebra.js and react-mathjax libraries to get it working in ES6. Because all these other packages are poorly maintained. For react-mathjax please use this repo.
Here's an example for showing fractions:
import React from 'react';
import { Fraction, toTex } from 'algebra.js';
import { Node, Context } from 'react-mathjax';
function Formula(props) {
return (
<Context input="tex">
<Node inline>{props.tex}</Node>
</Context>
);
}
export default function FractionDisplay() {
const a = new Fraction(1, 5);
const b = new Fraction(2, 7);
const answer = a.multiply(b);
const question = <Formula tex={`${toTex(a)} × ${toTex(b)} = ${toTex(answer)}`} />;
return (
<div>
{question}
</div>
);
}
Upvotes: 3
Reputation: 48
Oh no, I was so disappointed in myself when I found out what I was doing wrong. I applied display of Block to the Span element that renders the Latex (My take was that it would treat the whole chunk as one) and it put each Equation character onto a separate line. Changing the display to "inline" fixed the problem.
Upvotes: 0
Reputation: 608
Your logic is good but this is not the way react works. Instead of using MathJax why you don't use react-mathjax or react-formula-beautifier. And use them just like another component (which is how react is intended to work).
Here you have the oficial example.
Advise: If you want to use some lib in react, try to search react-nameoflib. Most libraries have his react version.
Upvotes: 1