react/javascript - TypeError: Cannot read property 'classList' of null

781 views Asked by At

Using React, I have a fixed nav cart icon that changes on scroll, with a link to the cart page/component. Whenever I click on the icon it navigates to the page, but after a moment brings up the error - TypeError: Cannot read property 'classList' of null. The cart page only has an 'in development...' div, no styling.

I've found the crux of the problem; a getNumbers() redux function in UseEffect, which just increases the cart quantity in the icon as an item is added. If I comment this function out, the error disappears. Tried the function in a separate useEffect but no success.

I don't understand why the cart page is parsing an icon from a separate component, much less how to solve this problem without reverting to a class.

Anyone know of a solution?

const Homepage = (props) => {
    console.log(props);
    useEffect(() => {
        window.addEventListener("scroll", () => {
            const isTop = window.scrollY > 700;
            const fixed = document.getElementById("fixed");

            if (isTop) {
                fixed.classList.remove("disappear");
            } else {
                fixed.classList.add("disappear");
            }
        });
        getNumbers();
    }, []);

    return (
        <div className='Homepage'>
            <div className='Homepage-nav' id='fixed'>
                <Link to='/basket'>
                    <i className='fas fa-shopping-cart'>
                        <span
                            style={{
                                fontSize: "1rem",
                                paddingLeft: ".25rem"
                            }}
                        >
                            {props.basketProps.basketNumbers}
                        </span>
                    </i>
                </Link>
            </div>
            <Hero />
            <Shop />
            <Footer />
        </div>
    );
};

const mapStateToProps = (state) => ({
    basketProps: state.basketState
});

export default connect(
    mapStateToProps,
    { getNumbers }
)(Homepage);
2

There are 2 answers

0
CertainPerformance On

If you wanted this to work without the error, you should return a cleanup function from useEffect to de-attach the event listener that was added:

const scrollListener = () => {
  const isTop = window.scrollY > 700;
  const fixed = document.getElementById("fixed");
  if (isTop) {
      fixed.classList.remove("disappear");
  } else {
      fixed.classList.add("disappear");
  }
  getNumbers();
};

});
useEffect(() => {
  window.addEventListener("scroll", scrollListener);
  return () => {
    window.removeEventListener("scroll", scrollListener);
  }
}, []);

But it would be better to use state instead of mutating the DOM through querySelector. In React, only mutate elements directly when you can't do it through React itself:

const Homepage = (props) => {
    const [isTop, setIsTop] = useState(false);
    const listener = () => {
        setIsTop(window.scrollY > 700);
        // getNumbers();
    };
    useEffect(() => {
        window.addEventListener("scroll", () => listener);
        return () => window.removeEventListener("scroll", () => listener);
    }, []);

    return (
        <div className={`Homepage-nav ${isTop ? '' : 'disappear'}`}>
0
thorntj85 On

Thanks to the two commenters, really should have been amending state to begin with. The commenters code didn't change the icon on scroll though, despite fixing the initial error. Here's the solution I came up with.

const [isTop, setIsTop] = useState(false);

   const changeFixed = () => {
       if (window.scrollY > 700) {
           setIsTop(true);
       } else {
           setIsTop(false);
       }
   };

   window.addEventListener("scroll", changeFixed); 


<div className={`Homepage-nav ${isTop ? "" : "disappear"}`}>