Reputation: 1774
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
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>
);
}
Upvotes: 4
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
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