14

Is it possible to take HTML/JSX content from an external source and render it in dynamically in React? In our case we want to take content from the Wordpress API and render it on both the client and the server (we're using NextJS)

So, the Wordpress API returns a JSON response which includes a content property which is a string of HTML/JSX. the content would look something like this.

{
    content: "<div><Slider imageCount="5" galleryID="1"></Slider><span>This is an image gallery</span></div>"
}

So, as you can see it would be a mix of HTML and React components/JSX, represented as a string

I would use Axios to make a call to get the content (on both server and client using NextJS's getInitialProps() method), then I need to render it, but i'm new to react and I can see a couple of problems.

1) In React, JSX is compiled at build time, not run time, I can't see how to get round this (It would have been easy in Angular using $compile service for example).

2) As we don't know what components the content from Wordpress is going to use, we'd have to import every single one of them at the top of the page, the content may include a component or it may include a component, who knows?.

Right now, I'm thinking this isn't possible, which would mean we'd have to reconsider using React, but I'm really hoping somebody has an answer.

Any help would really be appreciated.

jonhobbs
  • 26,684
  • 35
  • 115
  • 170
  • You could maybe parse the string (with a regex matching only tags with capitals) to detect the classes used in it, and then replace those parts (``) with the rendered react, and then use `dangerouslySetInnerHtml`. Does it make sense ? – ChrisR Jul 26 '18 at 13:57
  • It makes sense, it's the middle bit "replace those parts with the rendered react" that I'm not sure how to do. Where would I do this? – jonhobbs Jul 26 '18 at 14:15
  • Why instead of fetching a string that might contain JSX, you can "build" the string on save, and when fetching you will need only the bundle that is the output of that "build", using `import('url-to-bundle')`, and then render it with React. – felixmosh Feb 19 '19 at 20:46
  • while not exactly what the OP is asking, if your looking to dynamically render react components from a seperate bundle at runtime, checkout my answer here https://stackoverflow.com/a/61823689/800619 – NSjonas May 15 '20 at 16:14

3 Answers3

10

Interesting problem!

You should try react-jsx-parser. I think it solves your problems. Not sure how it works with Next JS - I have no experience with Next JS.

Check out this sandbox: Edit 24r1ypp00p


You are right about all the components getting bundled. There is a workaround for that. :)

Check out this sandbox: Edit 24r1ypp00p

I've created a dynamicComponent that expects an import promise and returns a component.

I changed the way A, B and C components are imported in index.js. This way each dynamically imported component gets a separate bundle and is only requested when needed.

This should solve your second problem.

bamse
  • 4,243
  • 18
  • 25
  • That's very interesting, looks like it could work on the front-end as long as I import every React component at the top of the page that the CMS might output. Going to investigate this a bit further. – jonhobbs Jul 26 '18 at 14:18
  • `react-jsx-parser` seems to add the missing link: importing components in FE so they are available when/if [rendered dynamically](https://github.com/TroyAlford/react-jsx-parser#advanced-usage---injecting-dynamic-jsx) – bamse Jul 26 '18 at 14:21
  • In their example ComponentA, B, C, D are all imported at the top of the page so presumably end up in the bundle regardless of whether JSX-parser needs them to render the string. Unless I've misundersttod something. – jonhobbs Jul 26 '18 at 14:40
  • From my limited understanding of NExtJS it renders your page on the from and back end in the same way so I shouldn't have to do anything differend for the SSR part of it but I'm going to ask the NextJS community to make sure. I'm also not sure what the security implications are of fetching a string from my CMS using Axios and then parsing it on the front end? – jonhobbs Jul 26 '18 at 14:42
  • I've updated the answer to address the components getting all bundled. Security wise I don't know what to say :) I would call this a temporary solution until _things_ are migrated to something easier to maintain and more straight forward. Fetching strings from CMS and rendering it on the FE might prove to be unstable and hard to maintain but it could get you some time for migration. Hope it helps! – bamse Jul 26 '18 at 15:24
  • Thanks @bamse. I've marked as correct and will add the +250 reputation as soon as I'm allowed. This is not a temporary solution though. We want our clients to be able to use Wordpress to edit their content and we want to be able to build the site in React, so I'm not sure there ever will be a better solution. – jonhobbs Jul 26 '18 at 15:52
0

You can refer to the below link

https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

For the React Components part you can render an Static HTML Markup string using

https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup

But be sure that the html you get is from an authentic source and will not contain any malicious scripts

Gokul
  • 82
  • 8
  • From reading that link I'm not sure the second part will work. The markup needs to be rendered on both server and client and needs to be fully functional. – jonhobbs Jul 23 '18 at 17:06
  • In case of a fully functional dynamic component then you will need the components in both server and client. But however need not import all the components , You can try Dynamic Imports and splitting the code int hat way all your components will not be loaded at render https://reactjs.org/docs/code-splitting.html – Gokul Jul 23 '18 at 17:35
  • I'm sorry, I don't understand how this solves my problem. I don't need to use two different solutions fot HTML and components, I need something that will convert a string of HTML/JSX into a working react component and child components in Next JS, on front-end and back-end – jonhobbs Jul 23 '18 at 20:54
  • You will have to import all the components at the top and use them , that is the only solution i can think of :) , I added the code splitting link as an optimization for dynamic imports – Gokul Jul 29 '18 at 18:24
-2

You can Render external HTML/React components dynamically in React like this, simply in these quotation , content: `<div>${<Slider imageCount="5" galleryID="1"></Slider>}<span>This is an image gallery</span></div>

ends with these ` sign.

Salman Mehmood
  • 263
  • 2
  • 6