Programador
Programador

Reputation: 21

Variable undefined in ReactJS

So I want to make a sticky nav bar for my website in react and I have some javascript code and when i run it I get an error saying TypeError: Cannot read property 'remove' of undefined when I do Console.log(nav) it says that it is defined but when I do console.log(sticky) it says that it is not defined and that why I get the error because I am trying to run remove on something that it is not defined.

import React from "react"
import {Link} from "react-router-dom"
import './App.css';


export default function App (){
  const navStyle = {
     color: "white"
  };
    // When the user scrolls the page, execute myFunction
  window.onscroll = function() {myFunction()};

  // Get the navbar
  var nav = document.getElementsByClassName("nav");
  console.log(nav)

  // Get the offset position of the navbar
  var sticky = nav.offsetTop;
  console.log(sticky)

  // Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
  function myFunction() {
    if (window.pageYOffset >= sticky) {
      nav.classList.add("sticky")
    } else {
      nav.classList.remove("sticky");
    }
  }


  return (
    <div className="App-header">
      <nav className="nav">
        <h3>Logo</h3>
        <ul>
          <Link style={navStyle} to="/">
              <li>Home</li>
          </Link>
          <Link style={navStyle} to="LogIn">
            <li>Log In</li>
          </Link>
      </ul>
      </nav>
    </div>
  )
}

The error says that the problem is on the line nav.classList.remove("sticky")

Any help would be appreciated.

Thanks

Upvotes: 2

Views: 137

Answers (2)

Swaraj Gandhi
Swaraj Gandhi

Reputation: 714

You forget to access the first element of the nav class. You were trying to get the property from the array of elements, which is not correct.

This should work:

import React from "react";
import "./styles.css";

export default function App() {
  const navStyle = {
    color: "white"
  };
  // When the user scrolls the page, execute myFunction
  window.onscroll = function () {
    myFunction();
  };

  // Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
  function myFunction() {
    var nav = document.getElementsByClassName("nav")[0];
    var sticky = nav.offsetTop;
    if (window.pageYOffset >= sticky) {
      nav.classList.add("sticky");
    } else {
      nav.classList.remove("sticky");
    }
  }

  return (
    <div className="App-header">
      <nav className="nav">
        <h3>Logo</h3>
        <ul>
          <li>Home</li>
          <li>Log In</li>
        </ul>
      </nav>
    </div>
  );
}

Link: https://codesandbox.io/s/compassionate-bush-w6304?file=/src/App.js:0-823

Upvotes: 1

Maheer Ali
Maheer Ali

Reputation: 36594

The mistake is that you getElementsByClassName returns a list of elements. You only need to get first element. But this is not the correct way of doing this thing with react hooks. You should use useRef and useEffect hooks

import React from "react"
import {Link} from "react-router-dom"
import './App.css';


export default function App (){
  const navStyle = {
     color: "white"
  };
  const navRef= useRef(null);
  

  useEffect(() => {
    window.addEventListener('scroll', myFunction);
    () => { window.removeEventListener('scroll', myFunction) }
  }, []) 
  // Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
  function myFunction() {
    var nav = navRef.current
    console.log(nav)

    // Get the offset position of the navbar
    var sticky = nav.offsetTop;
    console.log(sticky)
    if (window.pageYOffset >= sticky) {
      nav.classList.add("sticky")
    } else {
      nav.classList.remove("sticky");
    }
  }


  return (
    <div className="App-header">
      <nav ref={navRef} className="nav">
        <h3>Logo</h3>
        <ul>
          <Link style={navStyle} to="/">
              <li>Home</li>
          </Link>
          <Link style={navStyle} to="LogIn">
            <li>Log In</li>
          </Link>
      </ul>
      </nav>
    </div>
  )
}

Upvotes: 2

Related Questions