Inserting HTML fragments without an element container in React - reactjs

Our React app uses universal rendering. The html/body/head elements of the page are generated server-side using a React component. Normally, we can create things like <script> and <link> elements in our <head> just fine via JSX. Unfortunately, things got tricky once we started needing to insert third-party HTML fragments. These fragments are essentially a string like '<script src="some/url.js"></script><link rel="stylesheet" href="/some/css">'. Normally, HTML fragments can be injected into some element container via dangerouslySetInnerHTML, but there are no container elements for the <head> of an HTML document. This has forced us to either:
Parse the HTML fragments (no easy task) and convert them into React elements
Abandon JSX and build all our head content as one big concatenated/templated string
Is there any way in React to inject an HTML fragment into a document without a container element?

I think a combination of React Helmet to set the <head> at a component level and Interweave to inject/parse the HTML without using dangerouslySetInnerHTML could achieve what you're looking for?

Related

React JS and css pseudo element ::after ::before

As a React beginner I'm currently struggling with it for rendering styled components with the use of pseudo elements ::after and ::before.
Here is the sass style for a button: https://jsfiddle.net/r8qwhfvx/
It is what I try to achieve in React: changing the style of my button on hover using pseudo elements.
But how to use ::after / ::before in the className of button components for instance? JSX syntax unable the use of ::after / ::before in the components className.
I'm just able to write this:
return(
<button className='infoBtn'></button>
);
Please check jsfiddle link.
className JSX attribute is a string variable, which will be set as the class attribute value on the HTML element when it will be rendered by React. CSS pseudo elements can appear in CSS code, not as a class name for a HTML element.
So you need to give a class name to your button using className JSX attribute, then define CSS rules for this class. To do so you need to choose a strategy to setup CSS in your React app. There is multiple solutions :
use a plain old CSS file imported in your index.js or index.html
use a plain old style element in your index.html (these 2 options are global, like in plain old 90's web development)
use JSX "style" attribute : <Component style={{here put CSS object}} /> : https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/
use CSS modules (if you are using create-react-app) : https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/
use styled-components or any other CSS-in-JS option, there is a lot of solutions, I mention styled-components since it is one of the most popular
With all of these options you will be able to use CSS pseudo-element. For SASS you may have to setup a CSS preprocessor. If you are using create-react-app (https://create-react-app.dev/docs/adding-a-sass-stylesheet/) or styled-components (https://styled-components.com/docs/faqs#can-i-nest-rules) you're good to go, it's build in. Well for styled-components I'm not sure if it is a true full SASS support though.
Good luck with that !

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

Load static svg file in react and add dynamic styling

I am trying to load an SVG containing a map of country regions and then dynamically colorize the paths based on other data in the render function.
Is there a way in react to load a static SVG file at build or runtime and modify styles dynamically when rendering based on properties passed in?
You can use https://www.npmjs.com/package/react-samy-svg . This is how you can load an svg file and change an attribute. (No need to paste the svg code into the jsx)
<Samy path="https://raw.githubusercontent.com/hugozap/react-samy-svg/master/examples/1.svg">
<Proxy select="#Star" fill="red"/>
</Samy>
A Proxy element will select an svg element (using CSS selectors) and forward all its props to the selected element as attributes.
There is nothing hard about it.
Loading SVG file - just use $.ajax call for the resource, with dataType: 'text'
Use dangerouslySetInnerHTML to put it anywhere.
Changing of colors really depends on the way your SVG is structured. Ideally you should be able to change colors just using CSS (e.g. swap classes or generate style dynamically). If everything else fails, SVG is just text so you can do any text processing (color replacement) between steps 1 and 2.
I think it would be quite tough if even possible.
There are some approaches that claim to solve similar problem of converting string to react components (react-jsx-parser, html-to-react), or alternatively you can try converting html -> JSX -> JS (last step using babel) and subsequently requiring resulting js to obtain generated component.
Taking into account complexity of the steps above it might be simpler just to render SVG as html content of some div (using dangerouslySetInnerHTML) and later modify its styles using JS/jquery directly.

Does react will convert html snippets set in dangerouslySetInnerHTML to virtual DOM?

I use some DOM string manipulation libraries to generate HTML string and then inject them to some React components using dangerouslySetInnerHTML in my project, does react will add them to the virtual DOM? Can I still get the performance benefits from React in this way?
Yes and no. They're represented as string props, and the current html string as a whole is compared to the previous string using the equality operator.
There's no checking within the strings, or parsing the html into virtual dom. You can parse the html yourself, or modify the code generating it to output virtual dom instead.

Resources