Reputation: 21
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
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
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