How to pass react component into dangerouslySetInnerHtml? - reactjs

Suppose I cannot change this statement in my sourcecode:
<div dangerouslySetInnerHTML={{ __html: template }} />  
How can I replace the template for a react component? Like:
<div dangerouslySetInnerHTML={{ __html: someReactComponent }} />  
How can in insert a reactjs component in ?

As commented by FrankerZ,
Why do you even have to do this? <div><someReactComponent /></div>. There's a reason why it uses the word "dangerously"...avoid using it if you have to.
Yes, obviously. You shouldn't be using dangerouslySetInnerHTML most of the time as far as possible.
If you are trying to render static markup, then you may use renderToStaticMarkup. The linked post has also stated that but will not work because it is being used from React instance. You need to use it from ReactDOMServer:
import ReactDOMServer from 'react-dom/server';
ReactDOMServer.renderToStaticMarkup(statticElement)
This doesn’t create extra DOM attributes that React uses internally, such as data-reactroot. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes.
See the docs for more information on it.

Related

Underline syntax with react-markdown

I'm currently running into a problem that I can't solve (I've been searching for solutions since this morning, but I can't manage to find what I need).
I created a React app using react-markdown, allowing the user to edit some post-its, whose content is stored in Markdown format in my DB. But the thing is, I discovered there was no way to underline a text (I thought that if you could do it on Discord, then it means that it's the same in Markdown).
What I'd like is a solution allowing me to simply transform this:
**Bold text**
__Underlined text__
Into... well... you know what I mean. It doesn't have to be this exact syntax, but at least something similar. The only thing I've found is to create custom components, which I don't want because it requires using an already existing syntax, or, to convert the Markdown with replace() functions and use dangerouslySetInnerHTML to display it, which I don't want either, because isn't it called "dangerouslySetInnerHTML" for a reason?
I'd really appreciate if someone could help. And by the way, sorry for any grammar mistakes, English isn't my native language...
Right now there are no identifiers for underlining text in markdown syntax.
But as you know we can achieve it by using html tags in our markdown.
But we don't have to use dangerouslySetInnerHTML in react-markdown for parsing HTML tags. react-markdown (Check Appendix A: HTML in markdown) uses a plugin rehype-raw.
You can question the thing that rehype-raw internally implements allowDangerousHtml:true, but to prevent this , we can wrap our markdown content around Dompurify.sanitize() to reduce code vulnerablity.
I also faced the same problem , so this is the approach I tried and it worked for me .
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import DOMpurify from 'dompurify';
import "./styles.css";
export default function App() {
const markdown = `
**Parsing html in react markdown**
<u>underlined text</u>
`;
return (
<div className="App">
<ReactMarkdown rehypePlugins={[rehypeRaw]}>
{DOMpurify.sanitize(markdown)}
</ReactMarkdown>
</div>
);
}
CodeSandBoxLink

Adding markup on string without dangerouslySetInnerHTML

I have a modal component that receives two strings from a home component, it's easy to take those strings and render them on one single string with the correct markup on the modal.tsx with this
return <>No markup: {firstString}, with markup: <strong>{secondString}<strong><>
But what I actually want to do is render the whole string first in the other component to keep the modal component agnostic and just render whatever string and its markup.
The problem is that on the home component if I store the string with markup on state, I then have to use dangerouslySetInnerHTML on the modal.
Home.tsx
const message = `No markup: {firstString}, with markup: <strong>{secondString}<strong>`
Modal.tsx
<div dangerouslySetInnerHTML={{ __html: message }}>{}</div>
Is there another way to do this, and if not is this actually dangerous?
In terms of directly inlined HTML it is a potential XSS vulnerability.
That's why React, as well as other frameworks, try to make such places explicit and conspicuous.
But in your particular case, you control "inlined HTML" by React:
const message = `No markup: {firstString}, with markup: <strong>{secondString}<strong>`
XSS vulnerability is more about user input.
You have one more option to make "inlined HTML" as safe as possible (including user input) - use Markdown for example)
Gatsby - is a good example of Markdown usage in the React world
https://www.gatsbyjs.com/docs/how-to/routing/adding-markdown-pages/

prevent ReactJs component sent from rendering

I use the component that receives texts typed by the client, but clients happen to type in codes (such as an iframe), and dangerouslySetInnerHTML lets it render!
I would like it to show the code on screen (and I already tried to convert it to a string etc.) but not to render it.
<p dangerouslySetInnerHTML={{ __html: message }}></p>
If you don't want the message to be dom, then why use dangerouslySetInnerHTML in the first place?
<p>{message}</p>
use dompurify, useful for these scenarios, but i am not really sure how you are not able render this, posting a code snippet would help.

Is it possible to hydrate (or something else) single component?

My case: I have a page preloader, but it makes using react and it's to long (first paint). SSR could solve this problem, but it's too difficult (I mean solving this problem by full SSR).
I want to use something like React.hydrate but for one single component.
I have <MyCustomPreloader /> component which renders <div class="loader" />, but it render with a long delay (after loading the page).
My idea: For example, inside index.html I can make <div class="loader" /> which will be visible at first paint. Main problem say <MyCustomPreloader /> that I have already rendered div and he must use it without creating new.
I could find the necessary DOM inside the component and work with it, but this means abandoning React and continue to work directly with the DOM component.
I tried to manually add <div class="loader" /> into <div id="root"></div> and use React.hydrate instead of React.render and it works! But React.hydrate tries to hydrate every components before and after loader and this solution is kludge.
I believe that there is a function that can partially hydrate a single component (say to component "use this DOM" instead of making same new element), but I cannot find it.
For example:
const loader = ReactDOM.someMagicFunction(<MyCustomPreloader />, document.getElementById("loader"))
Example of this kludge: https://codesandbox.io/s/hopeful-meadow-qgz6j Description: I have "pre-rendered" loader in index.html, and react after loooong loading gets it and USED it (this DOM element).
Can I hydrate single component with some DOM element?

How to access a React element that has been rendered with renderToString and added with dangerouslySetInnerHTML?

EDITED: I corrected how I do inject the code, it is not MDX related, it is simply plain html
I have html code that I insert to my React page with
dangerouslySetInnerHTML={{ __html: myContent }}
Before, I've added some components to myContent with a simple regex.replace(), where I've replace some plain text with a React component transformed into plain html with
ReactDOMServer.renderToString(<Input type="text" ref={inputRef}/>)
*<Input> is a styled component that returns a <input> element
However, I cannot access to inputRef, nor any onClick or onChange works
I do think that to enable these event listeners I should hydrate the component? Don't really know how it would apply here, and don't really know if hydrate is supposed to be applied in this user case (no server involved)
So the objective is that I can interact when this <input> is changed, but so far it is absolutely static html that I cannot access to
What could I do?
At the end I've added an <input id="blah"... and access it with vanilla JavaScript without any apparent trouble

Resources