Kal
Kal

Reputation: 1774

How to convert JSON to Html in a React App

How to convert JSON to normal html with html elements in a react app?

Note that dangerouslySetInnerHTML can be dangerous if you do not know what is in the HTML string you are injecting

According to react docs -

dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it’s dangerous.

I have created a code sandbox below: https://codesandbox.io/s/relaxed-sunset-tlmr2?file=/src/App.js

The output just renders as string instead of html elements.

Here is my code:

import React from "react";
import "./styles.css";

const blocks = {
  time: 1602725895949,
  blocks: [
    {
      type: "header",
      data: {
        text: "This is a heading",
        level: 2
      }
    },
    {
      type: "paragraph",
      data: {
        text: "This is a paragraph"
      }
    }
  ]
};

export default function App() {
  function convertToHtml({ blocks }) {
    console.log(blocks);
    var convertedHtml = "";
    blocks.map((block) => {
      switch (block.type) {
        case "header":
          convertedHtml += `<h${block.data.level}>${block.data.text}</h${block.data.level}>`;
          break;
        case "paragraph":
          convertedHtml += `<p>${block.data.text}</p>`;
          break;
        default:
          console.log("Unknown block type", block.type);
          break;
      }
    });

    return <React.Fragment>{convertedHtml}</React.Fragment>;
  }

  return (
    <div className="App">
      <h1>JSON to html below</h1>
      {convertToHtml(blocks)}
    </div>
  );
}

Upvotes: 2

Views: 8007

Answers (3)

Linda Paiste
Linda Paiste

Reputation: 42170

When you are generating HTML in React you don't want to treat it as a string, you want to treat it as components. Instead of returning a literal string '<p>${block.data.text}</p>' you can return <p>{block.data.text}</p> which is valid JSX.

I've converted your switch statement into a function component which renders a single block. Note that null is the standard return for a component which doesn't render anything. For the case where you are making h1, h2, etc. dynamically, I saved that string as a capital letter variable so that React interprets it as a custom component instead of a built-in element.

export function Block({ type, data }) {
  switch (type) {
    case "header":
      const Element = "h" + data.level;
      return <Element>{data.text}</Element>;
    case "paragraph":
      return <p>{data.text}</p>;
    default:
      console.log("Unknown block type", type);
      return null;
  }
}

Then you can loop through the array of blocks and pass each block off as props to the Block component. Whenever you return elements from a loop, react throws a warning if you don't set a key, so I am using the array index as the key.

export default function App() {
  return (
    <div className="App">
      <h1>JSON to html below</h1>
      {blocks.blocks.map((block, i) => (
        <Block key={i} {...block} />
      ))}
    </div>
  );
}

Code Sandbox Link

Upvotes: 4

Ricardo
Ricardo

Reputation: 366

I have another answer.

Try this one. Now without dangerously HTML stuff.

import parse from "html-react-parser";

return <React.Fragment>{parse(convertedHtml)}</React.Fragment>;

Package: https://codesandbox.io/examples/package/html-react-parser

The same Code Sandbox

https://codesandbox.io/s/modern-glitter-1nnkc?file=/src/App.js:27-65

Upvotes: 3

Ricardo
Ricardo

Reputation: 366

You have to use the property dangerouslySetInnerHTML.

Like this:

return <React.Fragment>{<div dangerouslySetInnerHTML={{ __html: convertedHtml }} />}</React.Fragment>;

I also forked your Code Sandbox with the solution: https://codesandbox.io/s/modern-glitter-1nnkc?file=/src/App.js:1542-1674

Mark as answer if it works. Thanks

Upvotes: 2

Related Questions