Search code examples
htmlreactjsreact-dom

How to create childElement from server response in a react app


I created a react app with many nested routes.

One of my nested route is using a backend api that returns a complete HTML content.

And I need to display that exact content with same HTML and styling in my UI.

I'm able to successfully achieve it by manipulating the DOM according to axios response using createElement and appendChild inside useEffect method.

But, the whole philosophy behind using react is, to NOT modify the DOM and let react work on it by simly updating the states or props.

My question is: Is there a cleaner way to use api returned HTML in a react app?

Here is sample relevant code:

Item.js

...
...
useEffect( ()=>{  
    const fetchAndUpdateItemContent = async () => {
      try {     
        const response = await axios.get(url);
       
        var contentDiv = document.createElement("div");
        contentDiv.innerHTML = response.data.markup;
        document.getElementById(‘itemContent’)
             .appendChild(contentDiv); 
       
      } catch (err) {
          .....
          console.error(err);
          ......
        }
      }
    };
    fetchAndUpdateItemContent(); 
  },[itemId])

  return (
   <div id=‘itemContent'/>
  );
}

What did NOT work

Ideally I should be able to have a state as itemContent in Item.js and be able to update it based upon server response like this. But when I do something like below, whole HTML markup is displayed instead of just the displayable content.

const [itemContent, setItemContent] = useState(‘Loading ...');

...
    useEffect( ()=>{  
        const fetchAndUpdateItemContent = async () => {
          try {     
            const response = await axios.get(url);
            setItemContent(response.data.markup)  
          } catch (err) {
              .....
              console.error(err);
              ......
            }
          }
        };
        fetchAndUpdateItemContent(); 
      },[itemId])
    
      return (

    <div id=‘itemContent'>
      {itemContent}
     </div>

Solution

  • You're actually trying to convert an HTML string to a JSX. You can assign it into react component props called dangerouslySetInnerHTML

    Eg:

    const Item = () => {
      const yourHtmlStringResponse = '<h1>Heading 1</h1><h2>Heading 2</h2>'
      return <div dangerouslySetInnerHTML={{__html: yourHtmlStringResponse}}></div>
    }
    

    You can try it here dangerouslySetInnerHTML-Codesandbox