Skip to content Skip to sidebar Skip to footer

React : Rendering A Syntax Highlighted Code Block

I'm working on an article system using React and JSX. My articles sometimes have code examples within their content. I have implemented highlight.js to add style to these blocks. M

Solution 1:

I use markdown with highlight and then innerHtml. This is from https://github.com/calitek/ProjectNotes.

'use strict';

var fs = require('fs');
varRemarkable = require('remarkable');
var hljs       = require('highlight.js');
let lodash = require('lodash');

var md = newRemarkable({
  highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (err) {}
    }

    try {
      return hljs.highlightAuto(str).value;
    } catch (err) {}

    return'';
  }
});

var rootDataPath = './data';

var getFile = function(clientData, doneCallBack) {
  let getNote = function(fileData) {
    var filePath = rootDataPath + '/filenotes.json';
    var notesReadCallBack = function(err, data){
      if (err) doneCallBack({fileData: fileData, noteData: {note: 'error'}});
      else {
        let noteData;
        var jsonData = JSON.parse(data.toString());
        let noteRecord = lodash.findWhere(jsonData, {nodeid: clientData.nodeid});
        if (noteRecord) {
          let noteIndex = lodash.indexOf(jsonData, noteRecord);
          noteData = jsonData[noteIndex];
        } else {
          noteData = {nodeid: clientData.nodeid, note: ""};
        }
        let returnObject = {
          noteData: noteData,
          fileData: fileData
        }
        returndoneCallBack(returnObject);
      }
    };
    fs.readFile(filePath, notesReadCallBack);
  }
  var fileReadCallBack = function(err, data){
    if (err) doneCallBack({note: 'error'});
    else {
      let inData = data.toString();
      let inFile = clientData.filePath;
      if (inFile.endsWith('.js') || inFile.endsWith('.json') || inFile.endsWith('.css')) {
        inData = '``` javascript\n' + inData + '```';
      }

      let outData = md.render(inData);
      getNote(outData);
    }
  };
  fs.readFile(clientData.filePath, fileReadCallBack);
};

I am doing the markdown rendering on the server. Then sending that to the component.

importReactfrom'react';

letFileCtrlSty = {
  height: '60%',
  marginBottom: '20px',
  width: '100%'
};

exportdefaultclassFileCtrlextendsReact.Component {
  render() {
    let htmlDivSty = {height: '100%', width: '100%'}
    if (this.props.fileData.startsWith('<pre>')) htmlDivSty.overflow = 'hidden';
    else htmlDivSty.overflow = 'auto';
    let fileHtml = {__html: this.props.fileData};
    return (
      <divid='FileCtrlSty'style={FileCtrlSty}><divdangerouslySetInnerHTML={fileHtml}style={htmlDivSty}></div></div>
    );
  }
}

Solution 2:

My solution was to implement a simple "markdown" like parser within my article view. The idea is to parse the markdown using regex and return JSX elements from those results. I'm not so good at regular expressions (this could probably be improved) but here goes :

module.exports = React.createClass({
//this regex matchs \n\n, all wrapping ** **, wrapping ''' '''mainRegex: /(\n\n|\*\*(?:[\s\S]*?)\*\*|'''(?:[\s\S]*?)''')/g,
titleRegex : /(?:\*\*([\s\S]*?)\*\*)/,
codeRegex : /(?:'''([\s\S]*?)''')/,

getInitialState: function() {
    return {
        content: []
    };
},

setContent: function() {
    if (this.props.htmlContent && !this.state.content.length) this.setState( {content: this.formatText(this.props.htmlContent) });
},

formatText: function(_text) {

    var _this = this;
    var _content = [];

    _text = _text.split(this.mainRegex);

    _text.forEach(function(_frag) {

        if (!/\n\n/g.test(_frag) ) {

            if (_this.titleRegex.test(_frag))  _content.push( {type: "h2", value: _frag.match(_this.titleRegex)[1] } );
            elseif (_frag!=="") _content.push({type: "p", value: _frag});

        } elseif (_this.codeRegex.test(_frag))  {

            _content.push( {type: "code", value: _frag.match(_this.codeRegex)[1] } );
        }

    });

    return _content;
},
render: function() {

    return<article>
        {this.state.content.map(this.renderText)}
    </article>;

},

renderText:function(_tag, i) {

    switch (_tag.type) {

        case"p":
            return<pkey={i}>{_tag.value}</p>;
            break;

        case"h2":
            return<h2key={i}>{_tag.value}</h2>;
            break;

        case"code":
            return<prekey={i}><codeclasName="js">{_tag.value}</code></pre>;
            break;

    }

},

componentDidUpdate: function() {

    this.setContent();
    this.highlightCode();

},

highlightCode: function() {

    var _codeBlocks = document.getElementsByTagName('code');
    for (var i = 0, j = _codeBlocks.length; i<j; ++i) {
        hljs.highlightBlock(_codeBlocks[i]);
    }

}
});

Post a Comment for "React : Rendering A Syntax Highlighted Code Block"