Add ld+json script tag in client-side React

Ashish Shetty picture Ashish Shetty · May 29, 2018 · Viewed 11.8k times · Source

I have currently build a React app. Since it's a SPA, it has a single index.html file. I want to add 2 "ld+json" script tags, i.e for reviews and bookmarks for a certain route.

I've injected the script tag in componentDidMount of that component but the Google Structured Data Testing Tool doesn't read that.

Is it because Google reads directly from index.html and since my script tags are bundled inside main.js, it cannot read it?

Is it possible to do this in client side React? Is server side rendering the only possible way to do it?

-- Detailed Explanation--- I currently want to implement a system like IMDB has i.e whenever we search for a movie in goole; the IMDB search result will show the rating of the movie in the google pages itself. To do that I've need to put a script in my index.html file

<script type='application/ld+json'>
  {
      "@context": "http://schema.org/",
      "@type": "Review",
      "itemReviewed": {
        "@type": "Thing",
        "name": "Name"
      },
      "reviewRating": {
        "@type": "Rating",
        "ratingValue": "3",
        "bestRating": "5"
      },
      "publisher": {
        "@type": "Organization",
        "name": "1234"
      }
    }
</script>

Since my app is an SPA, I cannot put this in my main index.html file.

My current approach: Suppose "/movies/inception" route renders "MovieDetail" component. So, I'm currently adding the script at the end of this component.

import React from 'react';
import JsonLd from '../path_to_JSONLD';

class MovieDetail extends React.Component {
 render(){
 let data = {
  "@context": "http://schema.org/",
  "@type": "Review",
  "itemReviewed": {
    "@type": "Thing",
    "name": "Name"
   },
    "reviewRating": {
     "@type": "Rating",
     "ratingValue": "3",
     "bestRating": "5"
    },
   "publisher": {
     "@type": "Organization",
     "name": "1234"
    }
  }
   return(
    <SOME COMPOENTS />
    <JsonLd data={data} />

 )
}

My JsonLd component

import React from 'react';

const JsonLd = ({ data }) =>
  <script
    type="application/ld+json"
    dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
  />;

  export default JsonLd;

So, when i inspect the component; i can see the dynamically added script tag. But, in the structure testing tool "https://search.google.com/structured-data/testing-tool" . It doesnt show the schema after validation. Hence, I asked whether it can be done via client side or SSR is only solution for this where i can give an updated index.html as a response.

I hope this clears the confusion. Thanks!

Answer

For me, React Helmet works well.

<Helmet>
    <script className='structured-data-list' type="application/ld+json">{structuredJSON}</script>
</Helmet> 

Where structuredJSON is something like result of such function:

export const structuredDataSingle = (prod, imgPath, availability) => {

    let data = {
        "@context": "http://schema.org/",
        "@type": "Product",
        "name": `${prod.title}`,
        "image": prod.images.map((item) => imgPath + item),
        "description": prod['description'],
        "url": location.href,
        "offers": {
            "@type": "Offer",
            "priceCurrency": `${prod['currency'] || "₴"}`,
            "price": prod['price'] ? `${parseFloat(prod['price'])}` : 0,
            "availability": `${availability}`,
            "seller": {
                "@type": "Organization",
                "name": "TopMotoPro"
            }
        }
    };

    // brand
    if(prod['brand']) {
        data['mpn'] = prod['brand'];
        data['brand'] = {
            "@type": "Thing",
            "name": `${prod['brand']}`
        };
    }

    // logo
    if(prod['logo']){
        data['logo'] = imgPath + prod['logo'];
    }

    return JSON.stringify(data);
};