Adding markup on string without dangerouslySetInnerHTML - reactjs

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/

Related

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

How to pass react component into dangerouslySetInnerHtml?

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.

React render component containing only function

I'm very very new to react (still learning). One thing I noticed is that component always have a return with HTML (jsx) as content.
But I was wondering if it's possible to create a component containing only functions. For example, in my footer I only have static content. Just plain text and a button to go to the homepage. So this is what I'm trying to do:
index.html
<body>
<main id="app"></main>
<footer id="footer">
<!-- Some other content -->
<button onClick={this.onButton}>Home</button>
</footer>
<script src="/app/bundle.js"></script>
</body>
Footer.js
class Footer extends React.Component {
onButton() {
console.log('Button clicked');
}
render() {
console.log('render');
return null;
}
}
render(<Footer/>, window.document.getElementById("footer"));
This way, the component gets executed and I can see the log, however, the button defined in the index.html is removed.
On the other hand, if I remove the render() from the component, I get this error:
Footer(...): No render method found on the returned component instance: you may have forgotten to define render.
One thing I forgot to mention before, and also based on the item 2 of #aks answer, about using plaing html to create the links is that it's going to reload the whole page if I don't use the React router I'm currently using.
So, for example, If I create a link on the fotter with plain html like this:
Contact
When clicking on the link everything else is going to reset, because the page is going to refresh.
This is why it would be better to just use a function from a component instead of using the whole html declared inside the component.
Nice question. I will answer your question in points:
Render method is a required method, you cannot do without it, it can return null, as you are already doing.
If you say that your footer is static markup and links to some part, You don't even need the js file. It is not required.
In case you have components for most other parts, the static content may look too verbose. You can put those content in the render method of the Footer component as make the index.html very clean. Then in case you need more features in future, you can add them safely.
I hope that helps!

Resources