1

I want to add meta tags on a React component with plain javascript without external libraries. I've added it in useEffect hook like this:

 useEffect(() => {
    const ogTitle = document.createElement('meta');
    const ogImage = document.createElement('meta');
    const ogDescription = document.createElement('meta');
    if(classPage?.name) {
     
      ogTitle.setAttribute('property', 'og:title');
      ogTitle.content= classPage?.name;
      document.getElementsByTagName('head')[0].appendChild(ogTitle);
    }

   if(classPage?.pictureUrl) {
    
     ogImage.setAttribute('property', 'og:image');
     ogImage.content= classPage?.pictureUrl;
     document.getElementsByTagName('head')[0].appendChild(ogImage);
   }
    
   if(classPage?.description) {
     ogDescription.setAttribute('property', 'og:description');
     ogDescription.content= classPage?.description;
     document.getElementsByTagName('head')[0].appendChild(ogDescription);
   }
  
     const ogUrl = document.createElement('meta');
     ogUrl.setAttribute('property', 'og:url');
     ogUrl.content = document.location.href;
     document.getElementsByTagName('head')[0].appendChild(ogUrl);
   

  }, [classPage]);

And I can see the result when I open chrome inspector, they are there in the head tag. But when I go to some other page I see that meta tags are appending below instead of replacing the values from the previous page. Like this:

<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">
<meta property="og:title" content="Testing 2">
<meta property="og:image" content="https://images.unsplash.com/photo-1616008783091-189d8c5efd61?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxODkyMzl8MHwxfHJhbmRvbXx8fHx8fHx8fDE2MjEzMzUzMzY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080">
<meta property="og:description" content="testing">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/myfirstclasscc319a1ab57e4874be991a346e6fa86e">
<meta property="og:title" content="My First Class">
<meta property="og:image" content="https://images.unsplash.com/photo-1623001398544-5c7f047842ca?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxODkyMzl8MHwxfHJhbmRvbXx8fHx8fHx8fDE2MjM4NjAwMjA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080">
<meta property="og:description" content="jhlghjul iuiuiu iouiuii">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/myfirstclasscc319a1ab57e4874be991a346e6fa86e">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">
<meta property="og:title" content="Testing 2">
<meta property="og:image" content="https://images.unsplash.com/photo-1616008783091-189d8c5efd61?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxODkyMzl8MHwxfHJhbmRvbXx8fHx8fHx8fDE2MjEzMzUzMzY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080">
<meta property="og:description" content="testing">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">

I tried with cleanup function like this:

return () => {
  ogTitle.removeAttribute('property')
  ogTitle.content = '';
  document.getElementsByTagName('head')[0].removeChild(ogTitle)
  ......
}

But got this error:

NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

So my question is how to achieve adding meta tags in React component with plain javascript, NO libraries

3 Answers 3

3

As mentioned the issue seems to be that you are creating the element every time. In my opinion it would be an idea to just make a meta adder function as below:

const metaAdder = (queryProperty, value) => {
  // Get an element if it exists already
  let element = document.querySelector(`meta[${queryProperty}]`);

  // Check if the element exists
  if (element) {
    // If it does just change the content of the element
    element.setAttribute("content", value);
  } else {
    // It doesn't exist so lets make a HTML element string with the info we want
    element = `<meta ${queryProperty} content="${value}" />`;

    // And insert it into the head
    document.head.insertAdjacentHTML("beforeend", element);
  }
};

You can then call this function and pass the property/name of the meta tag you wish to change along with the value. If the meta tag exists it will change the content otherwise it will create and insert it.

In your example:

  if(classPage?.name) { 
    metaAdder('property="og:title"', classPage.name)
  }

I have removed your second check for the existence of className as we have already checked that in the wrapping if statement.

If you wish to change a property other than the content you can alter the function to take an object.

Sign up to request clarification or add additional context in comments.

Comments

0

Your clean up function is:

  1. Creating an new meta element
  2. Removing the property attribute from it (even though it doesn't have one)
  3. Setting the content property to an empty string
  4. Trying to remove it from the head (even though you never added it to the head in the first place)

If you want to remove the element you previously added to the DOM then you need to get a reference to that element.

Creating a new element … creates a new element. It doesn't find the existing one.

You already have references to the meta elements in ogTitle and the other variables you created. Use those.

2 Comments

I tried it like this: return () => { ogTitle.removeAttribute('property') ogTitle.content = ''; document.getElementsByTagName('head')[0].removeChild(ogTitle) ...... } But still same error
You have a if(classPage?.name) { condition. Maybe that element was never added to the head in the first place.
0

You should remove the appended meta elements directly in the cleanup callback.

useEffect(() => {
  const ogTitle = document.createElement('meta');
  const ogImage = document.createElement('meta');
  const ogDescription = document.createElement('meta');

  if(classPage?.name) { 
    ogTitle.setAttribute('property', 'og:title');
    ogTitle.content= classPage?.name;
    document.getElementsByTagName('head')[0].appendChild(ogTitle);
  }

  if(classPage?.pictureUrl) {
    ogImage.setAttribute('property', 'og:image');
    ogImage.content= classPage?.pictureUrl;
    document.getElementsByTagName('head')[0].appendChild(ogImage);
  }
    
  if(classPage?.description) {
    ogDescription.setAttribute('property', 'og:description');
    ogDescription.content= classPage?.description;
    document.getElementsByTagName('head')[0].appendChild(ogDescription);
  }

  const ogUrl = document.createElement('meta');
  ogUrl.setAttribute('property', 'og:url');
  ogUrl.content = document.location.href;
  document.getElementsByTagName('head')[0].appendChild(ogUrl);
 
  return () => {
    for (const metaElement of [ogTitle, ogImage, ogDescription, ogUrl]) {
      metaElement.parentNode.removeChild(metaElement)
    }
  }
}, [classPage]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.