Reputation: 61
I've been struggling with this bug. I keep getting TypeError: Cannot read property 'classList' of null on my react application. I'm quite new to react so have been trying t figure out the issue with no avail. Here's the error and my component, anyone know what the problem is?
The TypeError Message as text:
←→1 of 8 errors on the page
TypeError: Cannot read property 'classList' of null
(anonymous function)
http://localhost:3003/static/js/main.chunk.js:8044:49
8041 | var value = window.scrollY;
8042 |
8043 | if (value > 100) {
> 8044 | document.querySelector('.header--fixed').classList.add('sticky');
| ^ 8045 | } else {
8046 | document.querySelector('.header--fixed').classList.remove('sticky');
8047 | }
View source
This screen is visible only in development. It will not appear if the app crashes in production.
Open your browser’s developer console to further inspect this error.
My Component/ code:
import React, { Component } from "react";
import {FaTwitter ,FaInstagram ,FaFacebookF , FaLinkedinIn } from "react-icons/fa";
import { FiX , FiMenu} from "react-icons/fi";
import Scrollspy from 'react-scrollspy'
import mypdf from "../../../public/assets/files/Sarah-Chosen-CV.pdf";
const SocialShare = [
// {Social: <FaFacebookF /> , link: 'https://www.facebook.com/'},
// {Social: <FaInstagram /> , link: 'https://www.instagram.com/'},
// {Social: <FaTwitter /> , link: 'https://twitter.com/'},
{Social: <FaLinkedinIn /> , link: 'https://www.linkedin.com/in/sarah-chosen/'},
]
class HeaderThree extends Component{
constructor(props) {
super(props);
this.menuTrigger = this.menuTrigger.bind(this);
this.CLoseMenuTrigger = this.CLoseMenuTrigger.bind(this);
this.stickyHeader = this.stickyHeader.bind(this);
// this.subMetuTrigger = this.subMetuTrigger.bind(this);
window.addEventListener('load', function() {
console.log('All assets are loaded');
})
}
menuTrigger() {
document.querySelector('.header-wrapper').classList.toggle('menu-open')
}
CLoseMenuTrigger() {
document.querySelector('.header-wrapper').classList.remove('menu-open')
}
stickyHeader () {}
render(){
window.addEventListener('scroll', function() {
var value = window.scrollY;
if (value > 100) {
document.querySelector('.header--fixed').classList.add('sticky')
}else{
document.querySelector('.header--fixed').classList.remove('sticky')
}
});
var elements = document.querySelectorAll('.has-droupdown > a');
for(var i in elements) {
if(elements.hasOwnProperty(i)) {
elements[i].onclick = function() {
this.parentElement.querySelector('.submenu').classList.toggle("active");
this.classList.toggle("open");
}
}
}
const { logo, color='default-color' } = this.props;
let logoUrl;
if(logo === 'light'){
logoUrl = <img src="/assets/images/logo/logo-light.png" alt="Digital Agency" />;
}else if(logo === 'dark'){
logoUrl = <img src="/assets/images/logo/logo-dark.png" alt="Digital Agency" />;
}else if(logo === 'symbol-dark'){
logoUrl = <img src="/assets/images/logo/logo-symbol-dark.png" alt="Digital Agency" />;
}else if(logo === 'symbol-light'){
logoUrl = <img src="/assets/images/logo/logo-symbol-light.png" alt="Digital Agency" />;
}else{
logoUrl = <img src="/assets/images/logo/logo.png" alt="Digital Agency" />;
}
return (
<header
className={`header-area header-style-two header--fixed ${color}`}
>
<div className="header-wrapper">
<div className="header-left d-flex align-items-center">
<div className="logo">
<a href={this.props.homeLink}>{logoUrl}</a>
</div>
<nav className="mainmenunav d-lg-block ml--50">
<Scrollspy
className="mainmenu"
items={[
"home",
"about",
"service",
"portfolio",
"blog",
"contact",
]}
currentClassName="is-current"
offset={-200}
>
<li>
<a href="#home">Home</a>
</li>
<li>
<a href="#about">About</a>
</li>
<li>
<a href="#service">Skillset</a>
</li>
<li>
<a href="#portfolio">Portfolio</a>
</li>
<li>
<a href="#contact">Contact</a>
</li>
</Scrollspy>
</nav>
</div>
<div className="header-right">
<div className="social-share-inner">
<ul className="social-share social-style--2 color-black d-flex justify-content-start liststyle">
{SocialShare.map((val, i) => (
<li key={i}>
<a href={`${val.link}`}>{val.Social}</a>
</li>
))}
</ul>
</div>
<div className="header-btn">
<a className="rn-btn" href={mypdf} download="Sarah-Chosen-CV.pdf">
<span>download CV</span>
</a>
</div>
{/* Start Humberger Menu */}
<div className="humberger-menu d-block d-lg-none pl--20">
<span
onClick={this.menuTrigger}
className="menutrigger text-white"
>
<FiMenu />
</span>
</div>
{/* End Humberger Menu */}
<div className="close-menu d-block d-lg-none">
<span
onClick={this.CLoseMenuTrigger}
className="closeTrigger"
>
<FiX />
</span>
</div>
</div>
</div>
</header>
);
}
}
export default HeaderThree;
Upvotes: 0
Views: 677
Reputation: 845
Adding event listeners in react components should happen when the component has its DOM representation is ready. componentDidMount
is called after the component is mounted and has a DOM representation. This is often a place where you would attach generic DOM events.
So try to move the code where you assign the listener for scroll
event to componentDidMount
lifecycle method. and also remove the event listener in componentWillUnmount
. What makes this more important is that React components will often be re-rendered, and the code to set up event listeners will have the opportunity to run many times. This can create errors by setting up multiple listeners where we're actually expecting a single listener run per event occurrence.
Additionally, React-based UIs are often used in single-page apps that exist within long-lived browser sessions. This creates an environment where memory leaks can become serious more often.
Check out this article from react: https://react-cn.github.io/react/tips/dom-event-listeners.html
and also this answer describe how to wrap a component with scrollWrapper that handles the scroll event
Upvotes: 1