Here are the most important changes.

We first capture in temporary variables the submitted values for the name and review using relevant CSS selectors.

Then, we change the state of the internal variables using the call to this.setState.

After these changes, you can see that submitting reviews works as we planned.

We could continue adding more functionality to manage all the reviews, etc. but we will stop here so we can move to add structured data to the page.

When I initially placed the React component script in the HTML HEAD, I go this error in the JavaScript Console.

A Hands-On Introduction to Modern JavaScript for SEOs

When I clicked on the error line reported submit_review.js:38, I was presented with the problematic code.

A Hands-On Introduction to Modern JavaScript for SEOs

I suspected the selector wasn’t working, so I set a breakpoint (green highlighted line 36) and refreshed the page. This halts the page rendering on this line and brings up the Chrome JavaScript debugger. I can click to step through the line and mouse over the variable domContainer, and it was null, which means there was no value.

I typed the selector line of code in the JavaScript Console and I got the value as expected. What was happening here?

In order to understand the issue, we need to read about the lifecycle of an HTML page.

When browser loads a page it goes through different phases and not all parts of the page are available. Everything is available when the page is fully loaded.

I am executing JavaScript code in the head that is trying to find content in the BODY, which has yet to fully load.

So, to fix this issue, I simply moved my component script to the bottom of the page. Right before the closing HTML BODY tag.

      <!-- Footer -->


                <div class="row">

                    <div class="col-lg-12">

                        <p>Copyright &copy; Home of the best cakes, 2018 | 

                            <a href="" target="_blank" rel="nofollow">HTML5 Templates</a></p>







               <!-- /.container -->


          <!-- Load our React component. -->

          <script src=""></script>




Adding Structured Data to our Recipe Page

Now that we have a basic recipe page with a barely functioning button, let’s add some structured data to help make our page stand out in the SERPs.

We are going to follow the steps in this codelab.

“Since our sample site is a recipe blog, we’re going to start with recipe structured data. Recipe structured data can provide a rich result that can include rich information, like a description of your recipe, cooking and preparation times, and nutrition information. Your content may also automatically enable a recipe badge for Google Images on mobile devices, voice guidance on the Google Home, and a content action on the Google Assistant.”

Google’s preferred format for structured data is JSON-LD. This is good because it dramatically simplifies implementation.

We can add all markup in a single place on the page and avoid the complication of nesting values.

<script type="application/ld+json">
"@context": "",
"@type": "Recipe",
"name": "Party Coffee Cake"

This is our work in progress implementation. We are specifying the page contains a recipe for a Party Coffee Cake. This page contains all the details we need to complete our implementation.

Please note that we need to specify the type as “application/ld+json”. By default, browsers assume “application/javascript”. We are also specifying as the markup type.

A Hands-On Introduction to Modern JavaScript for SEOs

After we add the remaining required properties, we can test them in the Structured Data Testing Tool. We can see all values organized and displayed nicely.

However, we can see a warning about a missing optional attribute.



The aggregateRating field is recommended. Please provide a value if available.

We are going to improve the markup by adding a nested Review element.

        "review": {

          "@type": "Review",

          "reviewRating": {

            "@type": "Rating",

            "ratingValue": "4",

            "bestRating": "5"


          "author": {

            "@type": "Person",

            "name": "Mary Stone"


          "datePublished": "2018-05-01",

          "reviewBody": "This cake is delicious!",

          "publisher": "The cake makery"


Then, we can add the missing AggregateRating.

        "aggregateRating": {

            "@type": "AggregateRating",

            "ratingCount": "18",

            "ratingValue": "4"


Finally, we can test the final markup again in the Structured Data Testing Tool.

A Hands-On Introduction to Modern JavaScript for SEOs

We got rid of the warning and if you hit preview you will see the image I presented above.

Generate JSON-LD Markup with JavaScript

It is good that we produced valid markup, but as the data is hardcoded, it won’t update the number of reviews as we add them.

Let’s put our new JavaScript skills to good use and fix this!

For illustration purposes, we will simply increase the number of reviews on the web page and the JSON-LD object when we submit a new review.

The same approach can be used to populate the JSON-LD object with data from the page. However, in practice the data for the JSON-LD object will come from a database, the same way as the content for the page is.

var json_str = `{

    "@context": "",

    "@type": "Recipe",

  "review": {

    "@type": "Review",

    "reviewRating": {

      "@type": "Rating",

      "ratingValue": "4",

      "bestRating": "5"


// Plus other elements


The important technique here is that I saved the whole hard-coded JSON-LD code in a JavaScript string variable. I used backticks to handle multiple lines of text.

function update_ratingCount(ratingCount){


    var jsonld = JSON.parse(json_str);

    jsonld.aggregateRating.ratingCount = ratingCount;

    return JSON.stringify(jsonld);


I used JSON.parse to convert the string to an object that makes it easy to reference any element in the JSON-LD structure.

See how I can navigate nested levels using dots in jsonld.aggregateRating.ratingCount. Then, after I update the ratingCount value, I need to convert the object back to a string for insertion into the page.

Finally, we need to update the render() function of our React component. It should perform the following additional steps:

  1. Extract the current number of reviews
  2. Increase them by one
  3. Update the page with the increased reviews
  4. Update the JSON-LD as well, but it will replace the whole script with the one generated by the function we created.
    if (this.state.submitted) {


        //get current reviews

        var review_count = document.querySelector("body > div > div:nth-child(4) > div.col-lg-12 > h2").textContent;

        review_count = review_count.split(" ")[0]

        //increase current rating count by one

        var count = parseInt(review_count);


        review_count = count.toString();

        //now that we have the new number of reviews. We can update the page and the JSONLD 

        document.getElementById("user_reviews").innerHTML = `${review_count} user reviews`;

        document.getElementById("jsonld").innerHTML = update_ratingCount(review_count);


        if( == ""){

      return `You submitted ${}`;


            return `${}, you submitted ${}`;



I tested this in Chrome and I can see the values updated under the developer tool’s element tab. It won’t work with the Structured Data Testing Tool because the changes are not permanent.

And there you have it. If you try these code snippets and the codelab yourself, you should have learned enough JavaScript to be dangerous!

Community Projects & Resources to Learn More

The best way to learn programming and JavaScript, in particular, is by practicing it. The more you do it, the better you get at it.

Don’t get discouraged by the initial obstacles, come back to them later with fresh ideas.

Here are some tutorials to get you warmed up.

  1. JavaScript Tutorial from W3C Schools
  2. The Modern JavaScript Tutorial
  3. CSS Selectors reference from W3C
  4. Getting Started with JavaScript Debugging

This year started with so much excitement around Python, coding, and automation in the SEO community.

So many cool projects, articles, videos and introduction guides.

I’m so glad that everybody is building off the work of each other and making the community stronger and more fun every day.

Here are some projects that I want to highlight.

Dan Leibson and gang not only created an amazing Lighthouse automation tool in Nodejs. They open-sourced it and got it featured by the Google Analytics Twitter account!

Rory Truesdale from Conductor just started learning Python last year and put together a crazily advanced notebook with so many valuable features. Very impressive!

Gefen Hermesh created a sophisticated clustering solution that leverages BERT.

JR Oakes has been coding incredible things. A mini internet that got big praise from John Muller and more recently an advanced keyword clustering algorithm.

Hülya Çoban put together this amazing notebook that helps plot Google Trends in Google Data Studio.
This is going to be an exciting year for sure.

More Resources:

Image Credits

All screenshots taken by author, February 2020

Source link