Home > Net >  Unable to display generated HTML ,from Showdown plugin, in React component
Unable to display generated HTML ,from Showdown plugin, in React component

Time:04-09

I'm using Showdown module to obtain HTML from markdown. I want to display the generated HTML in my React component. My converter is working fine generating the HTML: <h1 id="typeyourmarkdownbountyhere">Type your markdown bounty here…</h1>

But I get this error message: Uncaught Error: Target container is not a DOM element. Is there another/better way to display the generated HTML? Can anyone point what I'm doing wrong?

import { observer } from "mobx-react-lite"
import React from "react"
import * as ReactDOM from 'react-dom';
import Showdown from 'showdown'

import { useStore } from "../store/Provider"

const converter = new Showdown.Converter({
    tables: true,
    simplifiedAutoLink: true,
    strikethrough: true,
    tasklists: true,
})

function Bounties() {
    const store = useStore()

    return (
        store.bounties.map( bounty => (
        <div>
            <h3 key={bounty.id}>{bounty.title}</h3> 
            <div id="bountyBody"></div>
            {ReactDOM.render(converter.makeHtml(bounty.body), document.getElementById('bountyBody')) }
        </div>
        ))
    )
}

export default observer(Bounties)

CodePudding user response:

That error is thrown because you are trying to get a reference to a DOM node while it has still to be rendered on DOM itself. You could solve it by calling ReactDOM.render inside a useEffect with an empty deps array [], this way it would be executed after the first render, but you will notice that it would anyway not work as expected, since it will render a string representing HTML code, it won't parse it! ReactDOM.render is used to attach JSX code to a DOM node, while you are trying to pass an HTML string ( that' s what converter.makeHtml() returns ). So it would never work.

A working approach would be:

  • Convert Markdown to HTML
  • Transpile HTML/JSX to React first level API
  • Parse the transpiled code
  • Execute it as real JSX code

This is an example :

import React, { useMemo, useEffect } from 'react';
import Showdown from 'showdown';
const buble = require('buble');

const MarkdownToJSX = ({ md }) => {
  if (typeof md !== 'string') return null;
  const makeComponent = useMemo(() => {
    const converter = new Showdown.Converter({
      tables: true,
      simplifiedAutoLink: true,
      strikethrough: true,
      tasklists: true,
    });
    const html = `<>${converter.makeHtml(md)}</>`;
    const code = buble.transform(html).code;
    const makeComponent = Function('React', 'return '   code);
    return makeComponent;
  }, [md]);

  return makeComponent(React);
};

Check the working example https://stackblitz.com/edit/react-32m1ay

  • Related