Search code examples
reactjsreact-hooksmeta-tagsreact-helmet

Cannot add meta tags with React 18.2.0


Hi I've done a couple of projects in React but I am new to adding meta tags in React. I have tried the plugin react-meta-tags which doesn't work and have tried react-helmet which also doesn't work and get the following error in console:

Warning: Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://reactjs.org/link/unsafe-component-lifecycles for details.

  • Move code with side effects to componentDidMount, and set initial state in the constructor.

Please update the following components: SideEffect(NullComponent)

On searching this error it seems I cannot use react-helmet but instead should use react-helmet-async.

Unfortunately the examples of how to use it doesn't match my code at all so cannot get it working.

My pages are basically:

Index.js
App.js
|_ Home.js (/)
|_ Page1.js (/page1)
|_ Page2.js (/page2)

Here is my code so far:

index.js:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from "react-router-dom";


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <BrowserRouter>
            <App />
      </BrowserRouter>
  </React.StrictMode>
);

App.js

import './App.css';
import {Route, Routes, useNavigate } from "react-router-dom";
import Home from './pages/Home';
import Page1 from "./pages/Page1";
import Page2 from "./pages/Page2";
import NoMatch from "./components/NoMatch";
import React from "react"

function App() {
    const navigate = useNavigate();
  return (
    <>

                    <button onClick={(e)=>{navigate('/');}} >
                        Home
                    </button>
                    <button onClick={(e)=>{navigate('/page1');}} >
                        Page1
                    </button>
                    <button onClick={(e)=>{navigate('/page2');}} >
                        Page2
                    </button>

        
        <Routes>

            <Route exact path={'/'} element={<Home />} />

            <Route path={"/page2"} element={<Page2 />} />

            <Route path={"/page1"} element={<Page1 />} />


            {/*####   404 #####*/} 
            <Route path={"*"} element={<NoMatch />} />
        </Routes>
        </>
  );
}

export default App;

Home.js, Page1.js, Page2.js are all identical apart from the names that are changed:

import React from "react"


const Home = () =>{


    return(
        <>
            hello from Home
        </>
    )
}
export default Home

Over at the docs page for react-helmet-async the usage example is this:

import React from 'react';
import ReactDOM from 'react-dom';
import { Helmet, HelmetProvider } from 'react-helmet-async';

const app = (
  <HelmetProvider>
    <App>
      <Helmet>
        <title>Hello World</title>
        <link rel="canonical" href="https://www.tacobell.com/" />
      </Helmet>
      <h1>Hello World</h1>
    </App>
  </HelmetProvider>
);

ReactDOM.hydrate(
  app,
  document.getElementById(‘app’)
);

But I have no idea which page that is supposed to go on or where in my code it is supposed to go. I do not know what their "App" is referring to and I do not have an element anywhere with an id of "app". I have tried applying this code to all of my pages and just get errors.

Does anyone know how to get this working or any other way to get meta tags (titles and meta descriptions) working with the current version of React please?

Thanks.


Solution

  • According to this issue, react-helmet is not maintained and has some issues with react-18. Here's a partial solution to your issue. This is what I use to dynamically update the title of the page.

    const usePageTitle = (title) => {
      const defaultTitle = "app-name";
    
      useEffect(() => {
        document.title = title || defaultTitle;
      }, [defaultTitle, title]);
    };
    
    function Demo() {
      usePageTitle("Demo");
      return <h1>Demo</h1>;
    }