0

I am changing the background-color of my navbar on scroll event, it works, but the problem is that the function changeNavBar is triggered on every scroll movement. I'd like to know how can I make it be triggered only at a certain point of the screen.

For instance, let's say the function should be called only when the YPosition is bigger than 50, once it is called it wouldn't be called again, unless the screen is scrolled up and the navbar reaches a point smaller than 50. In other words, we start at 0, it reaches 50 it is called, but it isn't called if the screen keeps being scrolled down, it won't be called it YPosition is 100, 200, 1000, doesn't matter. But if the page is scrolled up and reaches 50'inch it will be called.

This is my code:

const Navigation = props => {

let [navBg, setNavBg] = React.useState('transparent')

let navbarStyle = {
    backgroundColor: navBg
}

const changeNavBar = () => {
    if (window.scrollY > 50) {
        setNavBg('blue')
    } else {
        setNavBg('transparent')
    }

    console.log('test')
}

React.useEffect(() => {
    window.addEventListener('scroll', changeNavBar);
  
    return () =>
      window.removeEventListener('scroll', changeNavBar);
  }, []);



return (
    <div style={navbarStyle}>
        <Logo />
        <MenuNavigation />
    </div>
)
}

The issue is not what happens within the function changeNavBar. What I want is to prevent the function to be called when it is not necessary.

Berg_Durden
  • 1,531
  • 4
  • 24
  • 46
  • Check if the `navBg` is already transparent in the `else` condition, and only set it if isn't – yaakov Jul 08 '21 at 18:58
  • 1
    try using Intersection Observer API – sathya reddy Jul 08 '21 at 18:59
  • @sathya reddy Actually I don't know what this is, but I'll take a look. – Berg_Durden Jul 08 '21 at 19:05
  • @ggorlen Actually it doesnt. I had already found this answer and this is virtually the same as what I am doing. – Berg_Durden Jul 08 '21 at 19:12
  • OK, I think I read your title too literally. Do you really want it at exactly 50, or some threshold above and below? It's pretty unlikely the user will put the scroll at _exactly_ 50. Also, you'll likely want to debounce this and potentially use an [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) which should be more performant. Without debouncing, your handler will spam the component into rerendering hundreds of times on every scroll action. – ggorlen Jul 08 '21 at 19:24
  • @ggorlen I am reading the MDN documentation right now and trying to figure it out. `Without debouncing, your handler will spam the component into rerendering hundreds of times on every scroll action` - That's exactly what I am trying to prevent. – Berg_Durden Jul 08 '21 at 19:36
  • 1
    Maybe [How to slowdown/debounce events handling with react hooks?](https://stackoverflow.com/questions/54061464/how-to-slowdown-debounce-events-handling-with-react-hooks) is a better dupe suggestion? – ggorlen Jul 08 '21 at 19:40
  • @ggorlen it helps. It's not exactly what I am trying to do, but helps when it comes to rerendering. I'll keep looking for a way to reach what I want, but if I can't I'll implement that for now. Thank you. – Berg_Durden Jul 08 '21 at 19:57

1 Answers1

-1

Instead of performing state updates every time, check if it needs to be changed first.

const changeNavBar = () => {
    if (window.scrollY > 50) {
        if(navBg !== 'blue') setNavBg('blue')
    } else {
        if(navBg !== 'transparent') setNavBg('transparent')
    }
}
yaakov
  • 4,568
  • 4
  • 27
  • 51