Reputation: 33
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);
Upvotes: 0
Views: 788
Reputation: 33
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"}`}>
Upvotes: 0
Reputation: 371019
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'}`}>
Upvotes: 1