React : best way to inject Component in dynamically loaded HTML?

Viewed 2446

I'm new on React (I more at ease w/ jQuery or AngularJS). I have a special case and I don't find a good way to resolve it...

My app contains an area which is like a "document viewer". It loads an HTML content from the backend (via API, using Fetch) and inject it in the "viewer" component. The HTML content loaded looks like an "university report" (it's just a formatted text, only <span> and <p> with class="..." attributes, nothing more). Ex : <p>Lorem ispum <span>some text</span> loreb bis <span>ipsum</span></p> ...

I load the content, and inject it this way in the render() of my component <Viewer> : <div dangerouslySetInnerHTML={ getFreshlyLoadedHTML() } />

Easy, it works just fine !

But... Now, I want to inject some "interactive" components in the loaded HTML. For example, some button to give a feedback etc. The API must decide where to place the component between the words/nodes of the formatted text (HTML).
Ex : <p> Lorem ispum <span>some text</span> loreb bis <span>ipsum</span> <MyFeedbackButton paragraph="1.3"/> </p><p>Other Lorem Ipsum<p><span>...</span>

There, I'm stucked because I cannot use dangerouslySetInnerHTML if there are components inside the loaded HTML...

First attempt : I've tried modifying the API, and instead of sending the HTML in a string to the app, I send a custom JSON structure that represents almost the final JSX structure that I want. Then, in my react page, the render function only have to parse the JSON and build the JSX (here, a JsFiddle example if it's not clear : https://jsfiddle.net/damienfa/69z2wepo/34536/ )

It works, but I can't believe it's the good way...

I see a major problem : all the HTML node (span, p...) that I build from the render function are referenced by reactJs, is it really necessary ? Mostly, there are "dead" nodes (I mean, dom node that won't never changed, this is static formatted text).

Just take a look a all those "data-reactid" on nodes that never will be interactive... react problem

What would be your advice on that case ?

What about my attempt with a JSON-structure sent by the API ?

Is there a way to say to react "do not reference that element" ?

Do you clearly see a better solution to my problem ?

2 Answers

Try using an inline anonymous function within the inner content from within React using JSX. It works! Just be careful about how you wire up the data so there isn't a route where a user can inject HTML from an input or text field. <div className="html-navigation-button">{(() => { const CreateMarkup = ( sNavItemName :string ) => { return {__html: sNavItemName }; } var sTextToAddHtmlTo = props.nextNavItem.name.toString(); sTextToAddHtmlTo = sTextToAddHtmlTo.replace( "/", "/<wbr>" ); return ( <div dangerouslySetInnerHTML={CreateMarkup( sTextToAddHtmlTo )} > </div> ); })()} </div>

  • I didn't override the React internals of 'render()', but only used a React Component with props wiring to pass down data to it for rendering.
  • I added the hook for 'dangerouslySetInnerHTML' deep within the return content of the React Component so there would be no easy way to intercept and manipulate it.
  • As such, there is no 100% guarantee on safety, but that's where adding good security to web services, databases, and use of CORS and CORB would be helpful to lock down security risks.
Related