React Content Rendering
Tags: react, javascript
Published: 2023-09-02 08:15:10

Hello guys!

I am building my own combined CMS and ecommerce platform in React to meet my personal requirements. I needed an ability to create, edit, remove and view page content in the application - just to be easier to edit content, when project is in production. 

I want to share you my CMS approach and hear your opinions on this. In this posting I will show you, how the content is rendered - because I think that part is the more relevant.

There is two packages required in this approach and they are '[html-react-parser](https://www.npmjs.com/package/html-react-parser)' and '[dompurify](https://www.npmjs.com/package/dompurify)'.

**Let's begin**

First we have the component called Content. In my personal use case, Content component will get content ID as prop, so it can handle also logic to fetch content string from API.

In this example I am using HTML string, which we are rendering in the page. You may notice, that the htmlString has also some strange looking syntax, which starts with `{{` and ends with `}}`. 

It is syntax for components, because we want to have an ability to render also components with this solution.

For example, in my use case I might want to rended component that displays newest products, or top-selling items, etc.

We will also sanitize the htmlString by using 'dompurify' package to prevent XSS attacks and other bad things. 

```
import DOMPurify from "dompurify"
import parse from "html-react-parser"

const Content = () => {
    
   const htmlString = `
       <h1>Lorem ipsum</h1>
       {{
       ExampleComponent(
           text: 'Lorem ipsum',
           color: 'red'
       )
       }}
       <p>Lorem ipsum dolor sit amet.</p>
       <p>And the string continues ...</p>
   `
   
   const sanitizedHtml = DOMPurify.sanitize(htmlString)
   ...
}
```

Before moving on to parsing and rendering, we have to define what kind of component's are accepted to render. And don't forget to import components, if they are in other file!

```

const acceptedComponents = {
    ExampleComponent,
    OtherComponent
}
```

Okay, now we have sanitized our html string, defined accepted components and it is time move on to parsing and rendering the content.

```
...

function parseHtml(html) {

    // We will split our HTML in to parts
    const parts = html.split(/(\{{[^\}]+\}})/)

    // Then we will map every part and return them correctly
    return parts.map((part, index) => {
    
        // In cases the part is surrounded with {{ }}, we will try to find a component, handle props, which are surrounded in ( )
        if (part.startsWith('{{') && part.endsWith('}}')) {

            const content = part.substring(2, part.length - 2).trim()
            const [componentName, propString] = content.split(/\(|\)/)

            // Tarkistetaan löytyykö komponentin nimi sallittujen listalta
            const Component = acceptedComponents[componentName]

            if (Component) {
                const props = {}

                // If we find some props
                if (propString) {
                    const propPairs = propString.split(',')

                    // Let's map also props
                    propPairs.forEach(pair => {
                        const [propName, propValue] = pair.split(':').map(item => item.trim())
                            
                        if (propName && propName.match(/^[A-Za-z]\w*$/) && propValue && propValue.match(/^".*"$/)) {
                            props[propName] = propValue.replace(/"/g, '')
                        }
                    })
                }

                // Return component with or without props and continue to next part
                return <Component key={index} {...props} />
                }
                // To prevent errors, we want to also return message if component didn't found.
                else {
                    return <p key={index}>Component {componentName} not found</p>
                }
            }
            // If it is not component, we will parse HTML by using 'html-react-parser' package.
            return parse(part)
        })
    }
   
    // Component will return HTML parsed, showing HTML as HTMl and components as components, if found any.
    return parseHtml(sanitizedHtml)

```

What do you guys think of this approach? 😊