Search code examples
javascriptregexreactjsreact-dom

JSX Component + dangerouslySetInnerHTML?


So I am having trouble implementing this scenario:

From the backend server, I am receving an html string, something along like this:

<ul><li><strong>Title1</strong> <br/> <a class=\"title1" href="title1-link">Title 1</a></li><li><strong>Title2</strong> <a class="title2" href="/title2-link">Title 2</a>

Normally, that would be fine when just using dangerouslySetInnerHTML.

However, around the a href tags in the html, I need to wrap those in component like so:

<ModalLink href={'title'}>
    {Title}
</ModalLink>

This is because when wrapping the a tags, the component essentially adds functionality on creating a new child window.

I figured this is something you would need to implement on Regex, but I dont have the slightest idea where to begin.


Solution

  • You can deconstruct and extract the necessary values from your html string with regex and then use JSX instead of dangerouslySetInnerHtml. This component shows how to render your sample html string.

    import React, { Component } from 'react'
    
    export default class App extends Component {
        render() {
            const html = `<ul><li><strong>Title1</strong><br/><a class="title1" href="/title1-link">Title 1</a></li><li><strong>Title2</strong><br/><a class="title2" href="/title2-link">Title 2</a></li></ul>`
    
            return (
                <div>
                    <ul>
                    {html.match(/(<li>.*?<\/li>)/g).map( li => {
                        const title =  li.match(/<strong>(.*?)<\/strong>/)[1]
                        const aTag = li.match(/<a.*?\/a>/)[0]
                        const aClass = aTag.match(/class="(.*?)"/)[1]
                        const href = aTag.match(/href="(.*?)"/)[1]
                        const aText = aTag.match(/>(.*?)</)[1]
                        return (
                            <li>
                                <strong>{title}</strong>
                                <br/>
                                <a className={aClass} href={href}>{aText}</a>
                            </li>
                        )
                    })}
                    </ul>
                </div>
            )
        }
    }
    

    From there you can simply wrap the a tag in your ModalLink component. I'm not sure this is exactly how you want to do that, but here is an example.

    return ( 
        <li>
            <strong>{title}</strong>
            <br/>
            <ModalLink href={href}>
                <a className={aClass} href={href}>{aText}</a>
            </ModalLink>
        </li>
    )
    

    html.match(/(<li>.*?<\/li>)/g) matches each <li>...</li> within the html string in an array, which can then be mapped. Then I extract the title, href, etc. out of each <li>...</li> using captures (the part within parentheses), which can then be used in JSX. This answer provides more detail on the regular expressions used.