Closed kaushik94 closed 9 years ago
To suggest any "workaround" we need to know what was the problem :-) Can you provide any example that does not work?
@Sannis thanks for the quick response, my bad. In my index.html
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
In my react component
var Pretty = React.createClass({
render: function() {
return <pre className="custom-json-body"><code className="json">{JSON.stringify(this.props.json, null, 2)}</code></pre>;
}
});
But it isn't highlighting.
I tried with class
and className
as well. No luck.
hljs.initHighlightingOnLoad();
higlights code on page once after page is loaded.
If you need highlight dinamically loaded content - this is your responsability. We provide hljs.highlight()
method for that, so you can include it to React.js render
callback. I also think that React.js should provide some post-render events that you can listen and highlight rendered block there.
hljs.initHighlightingOnLoad(); higlights code on page once after page is loaded.
@Sannis thanks a lot. Its solved now. In fact I called hljs.initHighlightingOnLoad();
when the page has been loaded but I did not wait for that particular component to load.
I also think that React.js should provide some post-render events that you can listen and highlight rendered block there.
React provides this, just for future reference
var Pretty = React.createClass({
componentDidMount: function(){
hljs.initHighlightingOnLoad();
var current = React.findDOMNode(this);
hljs.highlightBlock(current);
},
render: function() {
return <pre className="custom-json-body"><code className="json">{JSON.stringify(this.props.json, null, 2)}</code></pre>;
}
});
Let me know if there is a better way to do this. Thanks a lot.
Great! Unfortunately, I'm not familiar with react to suggest something better. But it looks like you do double work in componentDidMount.
Ohh okay I just realised that for some reason hljs.initHighlightingOnLoad();
doesn't do anything at all. So finally its
componentDidMount: function(){
var current = React.findDOMNode(this);
hljs.highlightBlock(current);
}
Ohh okay I just realised that for some reason hljs.initHighlightingOnLoad(); doesn't do anything at all.
What it does is binds itself to the onload event of the browser which by that moment has probably already been fired. highlightBlock()
is the main method anyway.
For anyone (like me) who finds this issue: https://github.com/akiran/react-highlight :-)
import React from 'react'
import hljs from 'highlight.js'
import javascript from 'highlight.js/lib/languages/javascript'
import '../../node_modules/highlight.js/styles/darcula.css'
hljs.registerLanguage('javascript', javascript)
export class Highlighter extends React.PureComponent {
componentDidMount(){
hljs.highlightBlock(this.node)
}
render() {
let { children } = this.props
return (
<pre
ref={(node) => this.node = node}
>
<code className="javascript">
{children}
</code>
</pre>
)
}
}
export default Highlighter
<Highlighter>
{'function(){let test = [\'test\', \'test 2\']}'}
</Highlighter>
You can customize this component with various props like language
For anyone (like me) who finds this issue: https://github.com/akiran/react-highlight :-)
this library has a lot of side effects.
For anyone (like me) who finds this issue: https://github.com/akiran/react-highlight :-)
this library has a lot of side effects.
@Farhad33 Like what? I'm very interested to know, being that I just incorporated this package into my project.
For anyone (like me) who finds this issue: https://github.com/akiran/react-highlight :-)
this library has a lot of side effects.
@Farhad33 Like what? I'm very interested to know, being that I just incorporated this package into my project.
I have already experienced unstable DOMExceptions with this library and seen these errors posted as issues but unanswered...
For everyone who didn't find any working answer above and have no success with initHighlightingOnLoad
and others builtin functions.
React: 16.8.2 working example:
import hljs from "highlight.js";
import "./dracula.css";
class Preview extends Component {
componentDidMount() {
this.updateCodeSyntaxHighlighting();
}
componentDidUpdate() {
this.updateCodeSyntaxHighlighting();
}
updateCodeSyntaxHighlighting = () => {
document.querySelectorAll("pre code").forEach(block => {
hljs.highlightBlock(block);
});
};
render() {
return (
<div
className="content"
dangerouslySetInnerHTML={{ __html: this.props.parsedText }}
/>
);
}
}
Note that updateCodeSyntaxHighlighting
should be in componentDidMount
and componentDidUpdate
methods in every component which use <pre><code>...
tags.
I have a slightly different solution that registers only the language you actually need by importing them once.
React 16.8.2:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import hljs from 'highlight.js/lib/highlight'; // import hljs library
import 'highlight.js/styles/hopscotch.css'; // import your preferred style
const registeredLanguages = {}; // keep a record of registered languages
export class CodeHighlight extends Component {
constructor(props) {
super(props);
// do not show anything until language is loaded
this.state = { loaded: false };
// create a ref to highlight only the rendered node and not fetch all the DOM
this.codeNode = React.createRef();
}
componentDidMount() {
const { language } = this.props;
if (language && !registeredLanguages[language]) {
try {
const newLanguage = require(`highlight.js/lib/languages/${language}`);
hljs.registerLanguage(language, newLanguage);
registeredLanguages[language] = true;
this.setState(
() => { return { loaded: true }; },
() => { this.highlight(); }
);
} catch (e) {
console.error(e);
throw Error(`Cannot register and higlight language ${language}`);
// We can alternatively set loaded to true and show an error message in the
// code block instead of children, or just show the children without highlight.
// This would be an improvement or an optional behavior given a special prop.
}
} else {
this.setState({ loaded: true });
}
}
componentDidUpdate() {
this.highlight();
}
highlight = () => {
this.codeNode && this.codeNode.current && hljs.highlightBlock(this.codeNode.current);
}
render() {
const { language, children } = this.props;
const { loaded } = this.state;
if (!loaded) return ''; // or show a loader
return <pre>
<code ref={this.codeNode} className={language}>{children}</code>
</pre>;
}
}
CodeHighlight.propTypes = {
children: PropTypes.node.isRequired,
language: PropTypes.string,
};
// optionally set the language you think will use most as a default value
// if you don't set this, I would encourage to make language prop required,
// or at least improve the "else" statement in "componentDidMount"
CodeHighlight.defaultProps = {
language: 'javascript',
};
Usage:
// Use the default language, if set
<CodeHighlight>
{JSON.stringify(myObject, null, 4)}
</CodeHighlight>
// Specify a language
<CodeHighlight language="python">
{JSON.stringify(myObject, null, 4)}
</CodeHighlight>
Witaj @twistezo and ciao @vittoriozamboni
Do your codes support third-party languages like https://github.com/highlightjs/highlightjs-cypher?
Sure. Just import and register the 3rd party grammar after you import the main library.
WItaj @twistezo, ciao @vittoriozamboni and hello @yyyc514 !
Thank you, I have just updated the repo's README, adding React instruction.
After struggling for some time with these solutions, I stumbled across the highlight
and highlightAuto
methods. They seem designed for generating the highlights server-side, but work very nicely in a functional component.
import React from "react";
import hljs from "highlight.js"; // import hljs library
export function Highlighter(
content: string,
language?: string,
): JSX.Element {
const highlighted = language
? hljs.highlight(language, content)
: hljs.highlightAuto(content);
return (
<pre className="hljs">
<code
className="hljs"
dangerouslySetInnerHTML={{ __html: highlighted.value }}
/>
</pre>
);
}
Or highlight
if the component was aware of the language, etc... those are the two API calls for doing slightly more "manual" integrations, like building a component for a framework.
Thanks for making me aware of the highlight method, it's much faster. I updated the component.
it's much faster.
It should be, but most shouldn't notice unless you're highlighting a LOT of code.
@ExtraHash Thanks for the brilliant solution! I was looking for a simple hljs component to use with Next.js and your snippet did the trick. 🙏 I removed the className="hljs"
attribute on <code>
since the <pre>
tag already has hljs
className.
import React from "react";
import hljs from "highlight.js";
interface HighlighterProps {
content: string;
language?: string;
}
export default function Highlighter({
content,
language,
}: HighlighterProps): JSX.Element {
const highlighted = language
? hljs.highlight(language, content)
: hljs.highlightAuto(content);
return (
<pre className="hljs">
<code dangerouslySetInnerHTML={{ __html: highlighted.value }} />
</pre>
);
}
I am trying to configure highlightjs in a reactjs application to detect and highlight json. But it doesn't work, any workaround ? I need it on the browser side btw.