Originally posted on my website on May 24th 2020
Parsing Html returned by the Api in React
While playing around with React and the WordPress Rest Api, one thing that wasn't as straightforward as I thought was displaying the post content from the Api. It seems that React doesn't really like raw Html and the markup created by some blocks.
In my case I was trying to convert my own website to be a React app. On my site I make heavy use of the Github Gist block by CoBlocks to display code blocks. These blocks add script tags to my content that are rendered by React but are not being evaluated. Resulting in missing code blocks.
It took me some googling around to find a workable solution for this problem. So in this article I want to share with you what I found by building a small app together that renders the content of this blog post, which is kinda paradoxical if you think about it :p
Note that I will be focusing on my Github Gist problem, but you can use the technique described in this article to fix other (Block) content problems as well.
I've set up a CodeSandBox here with a working example for you to reference.
Fetching post content from the WordPress Rest Api.
To get started we first need to get the post data from the Api.
In the code snippet above we first use the useState hook to create some local state to store our post, and a setPost function to change this state when we receive the data from the Api.
We then use the useEffect hook to run when our component get mounted and execute a axios.get method to retrieve the contents of this post. When the response gets back we use our setPost function to store the data in the post state.
Lastly we render out a div with a h1 tag containing the post title and then a div containing the post content.
In this last step we see the problem we are facing. Being that react doesn't allow us to just render plain Html within our component. So we have to render an element and set the dangerouslySetInnerHTML attribute passing it our content.
Using dangerouslySetInnerHTML will display our html. But i was still left with my Github Gist block issue.
Parsing the Html to React elements.
After doing a bit of googling I came across the Html-react-parser package which converts an HTML string to one or more React elements.
In the changed code above we import the parse function from the Html-react-parser package. And on line 15 we swap out the dangerouslySetInnerHTML with a call to the Parse function passing it our Api post content.
While this code is much nicer to the eye this still didn't solve my Github Gist Problem. But reading through the Html-react-parser I had a little eureka moment.
Replacing elements with custom components
The Parse function converts Html elements to React elements but it also allows us to replace certain elements to specific react components ourselves.
To make things a bit cleaner we create a new React component called WpApiContent with the code above. Besides React we also import the Parse function again and a Gist component from the Super-react-gist package which will render and execute the Gist scripts.
Within our new component we simply return the result of the Parse function, but we pass Parse a second argument being a object of settings. For the settings we set a "replace" key and set that to a arrow function that accepts a domNode and gets called on every dom element the pare function encounters.
Inside this function we check if the nodes name is script and if the src attribute of this script contains the string "gist.github.com". With these to checks we can be certain that the current node is a Github Gist script.
If the node passes out checks we return a Gist component setting the url prop to the value of the scripts src attribute. We only need to remove the .js part from the url because the Gist component doesn't expect that and fails if we don't. So we use Javascript's Replace method to replace the .js part with a empty string.
Rendering the WpApiContent component
Now we just need to start using our new WpApiContent componentn in our little app.
Back in our App component we remove the import of the Parse package and replace it with a import of our new WpApiContent component. Then on line 15 we also replace the call to the Parse function with the WpApiContent component with a content prop passing it the post content.
Al this should now result in correctly parsed content comming trom the WordPress Rest Api .
NOTE: This technique doesn't account for any Xss problems. But since we are in complete control of the html coming from our WordPress site this should pose any problems. If you do want to address these problems you could have a look at the DomPurify package.
Completed code
Below you find the completed code for both the WpApiContent and App component. I've also set up a CodeSandBox here with a working example for you to reference.
The WpApiContent component
The App component.
Follow?
Let's connect on twitter @Vanaf1979 or here on Dev.to @Vanaf1979 so i can notify you about new articles, and other WordPress development related resources.
Thanks for reading and stay safe.
Top comments (0)