69

I've created a server-side react app, where it would return html as shown below:

const html = renderToString(<App />);
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <title>A Cool Page</title>
    <link rel="stylesheet" href="${ROOT}/static/index.css">
  </head>
  <body>
    <div id="root">${html}</div>
    <script src="${ROOT}/client-bundle.js"></script>
  </body>
</html>

I read a lot of people have been using react-helmet to manage the content in head. I'm wondering what's the benefit of using it, when I can just directly include as shown above.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
PBandJ
  • 2,537
  • 3
  • 21
  • 31
  • 1
    how do you change its content at runtime this way? – azium Oct 07 '18 at 17:02
  • Do you mean change the content of in the head? In what scenario would I want to change the content? Do you mean in the server-side I might want different content in the head compare to that on the client-side? @azium – PBandJ Oct 07 '18 at 17:15
  • 12
    Perhaps you don't quite understand how React works in this case: your server will send a real page when the use first hits a real URL, which includes a script that will load the app. Once the app is loaded, your server will _not_ get called again, and anything that would load "a different page" most definitely doesn't: React (if properly configured) uses libraries like React-Router to make it look to the user like they're changing from one URL to another through the history API, with `` updates, using `helmet`, but your users never _actually_ navigate away from that first page. – Mike 'Pomax' Kamermans Oct 07 '18 at 17:15
  • 5
    After reading all the answers to the original question, I still don't get it. Most answers seem to throw in SSR. What if IDGAF about SSR ? – joedotnot Dec 20 '20 at 05:07

6 Answers6

68

A major benefit of react-helmet is when you have multiple components in a tree with <head> tags, and you have <meta> tags with the same attributes/values.

For instance, if on your index page component you have:

const html = renderToString(<App />);
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <meta name="description" content="This is the index page description"> 
    <title>A Cool Index Page</title>
  </head>
</html>

But then on a leaf page component, you also have a <head> tag containing meta tags:

<html>
  <head>
    <meta name="description" name="This is the unique leaf page description"> 
    <title>A Cool Leaf Page</title>
    <link rel="stylesheet" href="${ROOT}/static/index.css">
  </head>
</html>

Notice between our two page components there are two meta tags with the same attribute value name="description" in our tree. You might think this could lead to duplication, but react-helmet takes care of this problem.

If someone ends up on the leaf page, react-helmet overrides the index/site-level description meta tag and renders the lower-level one, the one specifically for the leaf page.

It will also contain the viewport meta tag, since it did not have to be overwritten.

Because of react-helmet, on the leaf page, the <head> would appear as follows:

<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <meta name="description" name="This is the unique leaf page description"> 
    <title>A Cool Leaf Page</title>
    <link rel="stylesheet" href="${ROOT}/static/index.css">
  </head>
</html>
Dev Matee
  • 5,525
  • 2
  • 27
  • 33
Lexis Hanson
  • 777
  • 5
  • 8
  • 2
    If the app doesn't use server-side rendering, the meta tags wouldn't be any good for the crawlers? or would they? – Akber Iqbal Feb 26 '20 at 02:38
  • @AkberIqbal Nope, Most crawlers do not wait for javascript to set the meta tags or render the page at all except the popular ones ex. Google, etc. – Tero Mar 05 '20 at 23:24
  • 3
    @AkberIqbal Google does wait for javascript to render so does bing, yahoo and duckduckgo but in case of social platforms like facebook or twitter and reddit i guess they don't support it and need to be handled with workarounds. – Pooya Estakhri Mar 18 '21 at 08:01
  • same questino, will google be able to check the javascript present on the href? and any other attributes? – Rohan Devaki Aug 23 '21 at 14:50
23

react-helmet allows to set meta tags that will be read by search engines and social media crawlers. This makes server-side rendering and React Helmet a dynamic duo for creating apps that are SEO and social media friendly.

eg:

import { Helmet } from 'react-helmet';

<Helmet>
    <title>Turbo Todo</title>
    <meta name="description" content="test on react-helmet" />
    <meta name="theme-color" content="#ccc" />
</Helmet>
Sajin M Aboobakkar
  • 4,051
  • 4
  • 30
  • 39
8

Both methods should work. But with react-helmet, the head is also treated as a component and is more react-like. Also, although it's unusual, you may bind some props or states with the meta-data to implement a dynamic head. One scenario is switching between different languages.

Van
  • 3,749
  • 1
  • 15
  • 15
4

React Helmet also allow you to modify classes outside the scope of your render function.

For example, if you want to modify your <body> tag dynamically, you could do the following:

<Helmet>
    <body className="dynamic-class-for-body-on-this-view" />
</Helmet>
Alberto Ruiz
  • 376
  • 2
  • 8
4

React Helmet is a reusable React component that will manage all of your changes to the document head.

For example, if you want to change the title and meta description of every page according to your SEO, you could do the following:

<Helmet>
    <title>Your Title</title>
    <meta name="description" content="Description of your page" />
</Helmet>
Zsolt Meszaros
  • 21,961
  • 19
  • 54
  • 57
0

I specifically use Helmet for meta tags and to also change the style of a 3rd party component that isn't editable.

        <Helmet>
          <script type="text/javascript">
            {`
            window.addEventListener('load', function () {
                    document.querySelectorAll('.noEditStars > span').forEach(span => {
                    span.style.cursor = 'pointer';
                });
            }, false);
            `}
          </script>
        </Helmet>
Chad French
  • 61
  • 2
  • 4