0
votes

I am using the following code (useEffect) to change the class on scroll.

import { useState, useEffect } from "react"

export const useScrollHandler = () => {
  // setting initial value to true
  const [scroll, setScroll] = useState(1)

  // running on mount
  useEffect(() => {
    const onScroll = () => {
      const scrollCheck = window.scrollY < 10
      if (scrollCheck !== scroll) {
        setScroll(scrollCheck)
      }
    }

    // setting the event handler from web API

    document.addEventListener("scroll", onScroll)

    // cleaning up from the web API
    return () => {
      document.removeEventListener("scroll", onScroll)
    }
  }, [scroll, setScroll])
  return scroll
}

Even if I used cleanup function it gives the following error when I do history.push("/")

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

How to solve it?

Here I have used useScrollHandler.

function HomeNav() {
  const scroll = useScrollHandler()
  return (
    <React.Fragment>
      <nav
        className={
          scroll ? "navbar navbar-expand-lg navbar-light fixed-top py-3" : "navbar navbar-expand-lg navbar-light fixed-top py-3 navbar-scrolled"
        }
        id="mainNav"
      >
      </nav>
    </React.Fragment>
  )
}

export default HomeNav
2
Why have you given setScroll as a dependency in the second args array of useEffect? Also, can you add the code where you use useScrollHandler? - Utsav Patel
do you want to remove eventListener on unmount? - Sarthak Aggarwal
@SarthakAggarwal Yes. - Amiya Behera

2 Answers

0
votes

Try this to remove EventListener on unmount.

const onScroll = () => {
      const scrollCheck = window.scrollY < 10
      if (scrollCheck !== scroll) {
        setScroll(scrollCheck)
      }
}

useEffect(() => {

    // Add event listener on component mount
    document.addEventListener("scroll", onScroll)

    // removing event listener on component unmount
    return () => {
      document.removeEventListener("scroll", onScroll)
    }
}, []) // This useEffect will act as componentDidMount and return function as componentWillUnmount as no dependencies are given.


0
votes

I don't think you need scroll in the event handler, and setScroll is guaranteed to be constant, so that means your effect handler can use [] as its dependency array. Simplifying that might help.

import { useState, useEffect } from "react"

export const useScrollHandler = () => {
  // setting initial value to true
  const [scroll, setScroll] = useState(true);
  // running on mount
  useEffect(() => {
    const onScroll = () => setScroll(window.scrollY < 10)
    // setting the event handler from web API
    document.addEventListener("scroll", onScroll)
    // cleaning up from the web API
    return () => {
      document.removeEventListener("scroll", onScroll)
    }
  }, [])
  return scroll
}