Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toggle Class based on scroll React JS

I'm using bootstrap 4 nav bar and would like to change the background color after ig 400px down scroll down. I was looking at the react docs and found a onScroll but couldn't find that much info on it. So far I have...

I don't know if I'm using the right event listener or how to set the height etc.

And I'm not really setting inline styles...

  import React, { Component } from 'react';

   class App extends Component {

   constructor(props) {
    super(props);

      this.state = {  scrollBackground: 'nav-bg' };
      this.handleScroll = this.handleScroll.bind(this);
   }


   handleScroll(){
      this.setState ({
         scrollBackground: !this.state.scrollBackground
       })
    }

 render() {
 const scrollBg = this.scrollBackground ? 'nav-bg scrolling' : 'nav-bg';

 return (
   <div>

       <Navbar inverse toggleable className={this.state.scrollBackground} 
                                  onScroll={this.handleScroll}>
        ...
      </Navbar>

    </div>
   );
  }
}

export default App;
like image 428
Fernando B Avatar asked Jun 18 '17 06:06

Fernando B


3 Answers

For those of you who are reading this question after 2020, I've taken @glennreyes answer and rewritten it using React Hooks:

  const [scroll, setScroll] = useState(0)

  useEffect(() => {
    document.addEventListener("scroll", () => {
      const scrollCheck = window.scrollY < 100
      if (scrollCheck !== scroll) {
        setScroll(scrollCheck)
      }
    })
  })

Bear in mind that, useState has an array of two elements, firstly the state object and secondly the function that updates it.

Along the lines, useEffect helps us replace componentDidmount, the function written currently does not do any clean ups for brevity purposes.

If you find it essential to clean up, you can just return a function inside the useEffect.

You can read comprehensively here.

UPDATE:

If you guys felt like making it modular and even do the clean up, you can do something like this:

  1. Create a custom hook as below;

    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
    
    }
    
  2. Call it inside any component that you find suitable:

    const component = () => {
    
    // calling our custom hook
    const scroll = useScrollHandler()
    
    ....... rest of your code
    
    }
    
like image 198
Pouya Ataei Avatar answered Oct 17 '22 07:10

Pouya Ataei


One way to add a scroll listener is to use the componentDidMount() lifecycle method. Following example should give you an idea:

import React from 'react';
import { render } from 'react-dom';

class App extends React.Component {
  state = {
    isTop: true,
  };

  componentDidMount() {
    document.addEventListener('scroll', () => {
      const isTop = window.scrollY < 100;
      if (isTop !== this.state.isTop) {
          this.setState({ isTop })
      }
    });
  }
  render() {
    return (
      <div style={{ height: '200vh' }}>
        <h2 style={{ position: 'fixed', top: 0 }}>Scroll {this.state.isTop ? 'down' : 'up'}!</h2>
      </div>
    );
  }
} 

render(<App />, document.getElementById('root'));

This changes the Text from "Scroll down" to "Scroll up" when your scrollY position is at 100 and above.

Edit: Should avoid the overkill of updating the state on each scroll. Only update it when the boolean value changes.

like image 32
glennreyes Avatar answered Oct 17 '22 06:10

glennreyes


 const [scroll, setScroll] = useState(false);

 useEffect(() => {
   window.addEventListener("scroll", () => {
     setScroll(window.scrollY > specify_height_you_want_to_change_after_here);
   });
 }, []); 

Then you can change your class or anything according to scroll.

<nav className={scroll ? "bg-black" : "bg-white"}>...</nav>

like image 7
Basanta Kc Avatar answered Oct 17 '22 06:10

Basanta Kc