React.js: Set innerHTML vs dangerouslySetInnerHTML
Yes there is a difference!
The immediate effect of using innerHTML
versus dangerouslySetInnerHTML
is identical -- the DOM node will update with the injected HTML.
However, behind the scenes when you use dangerouslySetInnerHTML
it lets React know that the HTML inside of that component is not something it cares about.
Because React uses a virtual DOM, when it goes to compare the diff against the actual DOM, it can straight up bypass checking the children of that node because it knows the HTML is coming from another source. So there's performance gains.
More importantly, if you simply use innerHTML
, React has no way to know the DOM node has been modified. The next time the render
function is called, React will overwrite the content that was manually injected with what it thinks the correct state of that DOM node should be.
Your solution to use componentDidUpdate
to always ensure the content is in sync I believe would work but there might be a flash during each render.
Safe alternative to dangerouslySetInnerHTML
If XSS is your primary concern, you can use DOMPurify
to sanitize your HTML before inserting it in the DOM via dangerouslySetInnerHTML
. It's just 10K minified. And it works in Node too.
Alternative to dangerouslySetInnerHTML
Perhaps these parsers can fulfill ur need
html-to-react
html-react-parser
What are the pros and cons of using an HTML parsing package like html-react-parser vs dangerouslySetInnerHtml in React
I've recently been studying this issue for a Headless CMS project I'm working on. From what I understand:
dangerouslySetInnerHtml
creates DOM elements outside of ReactDOM.Render()
method, so it's not dynamically maintained by the React library. This basically defeats the purpose of using React in the first place (displaying and maintaining virtual DOM).
More concerning, though, is that it's vulnerable to Cross-Site Scripting (XSS) attacks, which is where it gets its name. These are a very common form of attack on the web. You can read about that here: https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
If you want the app to be less prone to attacks, you'll have to use a sanitization library like DOMPurify
for dangerouslySetInnerHtml
, so you're likely to have another dependency either way. Once you compile the app for production (npm build
) the minimization process makes the codebase extremely compact, and you can do some optimization beforehand with techniques like code-splitting, which makes each section of your page load only if requested, instead of all at once: https://reactjs.org/docs/code-splitting.html
I wouldn't worry too much about a few dependencies, personally - they're a fact of life on the modern web. I've been leaning towards using html-react-parser
, but I caveat that by saying I have not investigated whether it reduces XSS vulnerability. However, even if both are vulnerable to XSS attacks, at least html-react-parser
introduces the elements through ReactDOM.render()
so they don't make the DOM all catty-wompus - that sounds like a recipe for disaster down the road.
set innerHtml from a sanitized html is still dangerous?
But I sanitized my html with dompurify. Does this completely protect me from XSS attacks?
Likely yes, but it's not 100% guaranteed. If DOMPurify doesn't have bugs that will let XSS through, setting innerHTML
or dangerouslySetInnerHTML
with its results will be safe. DOMPurify is open-source and relatively popular, so if it did have such vulnerabilities, they would probably have been seen by now.
But, like with everything humans do, mistakes and coincidences that result in vulnerabilities not being seen are still possible.
Add Icon in dangerously set Inner html in React
You can simply put an icon on each item:
Assume that your keyArray
is something like this:
const keyArray = ["World", "Americas", "South", "America"];
Now, you can use map
function to add an icon for each item:
const result = data.map((item, i) => (
<div key={i}>
<ArrowRightIcon />
<span>{item}</span>
</div>
));
Now, the result
is ready to use, with a parent div
and flex
style, the final result will be produced:
<div style={{ display: "flex" }}>{result}</div>
How to run a loop inside a jsx string set using dangerouslySetInnerHTML
Since you want it to be a string, you must return a string inside the map()
, not a html element, change the stringJsx
to something like:
const stringJsx = (`
<ol>
${
items.map((item, index) => {
return `<li key=${index}>this is a nice item : ${item.name}</li>`;
}).join('')
}
</ol>
`);
Btw: consider using join('')
after the map so there won't be any ,
's in between the <li>
's
Full snippet using the above code:
class Example extends React.Component {
render() {
const items = [{name: 'nice'},{ name: 'bice'}, {name: 'tice'}];
const stringJsx = (`
<ol>
${
items.map((item, index) => {
return `<li key=${index}>this is a nice item : ${item.name}</li>`;
}).join('')
}
</ol>
`);
return (
<React.Fragment>
<h1 id='nice'> this is a nice h1 tag</h1>
<div dangerouslySetInnerHTML={{ __html: stringJsx }} />
</React.Fragment>
)
}
}
ReactDOM.render(<Example />, document.body);
:root{
--bg-clr-1: #E7F8F8;
--card-clr-red: #F03E3E;
--card-clr-violet: #7950F2;
--card-clr-green: #12B886;
--text-clr: #333;
}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
Related Topics
Show and Hide Divs At a Specific Time Interval Using Jquery
Why Is It Bad Practice to Use Links With the JavaScript: "Protocol"
Confirmation Before Closing of Tab/Browser
How to Avoid the Need For Ctrl-Click in a Multi-Select Box Using JavaScript
Replace HTML Page With Contents Retrieved Via Ajax
Changing the Selected Option of an HTML Select Element
How to Replace Text Inside a Div Element
Uncaught Error: Security_Err: Dom Exception 18 When I Try to Set a Cookie
How to Start Automatic Download of a File in Internet Explorer
How to Convert Base64 String to JavaScript File Object Like as from File Input Form
Programmatically Selecting Partial Text in an Input Field
Document.Write() Overwriting the Document
Html ≪Select≫ Selected Option Background-Color CSS Style
Want to Add "Addeventlistener" on Multiple Elements With Same Class
How to Write in File (User Directory) Using JavaScript
Fetch(), How to Make a Non-Cached Request