Home > Enterprise >  React JS detect active component and update navbar
React JS detect active component and update navbar

Time:01-29

I am new to React, so apologies if this is obvious.

I have several components on a single-page website. This is my App.js:

function App() {
  return (
    <>
      <Header />
      <Nav />
      <About />
      <Experience />
      <Portfolio />
      <Activities />
      <Contact />
      <Footer />
    </>
  );
}

This is the Nav component:

const Nav = () => {
    const [activeNav, setActiveNav] = useState('#');
    return (
        <nav>
            <a href='#' onClick={() => setActiveNav('#')} className={activeNav === '#'? 'active': ''}><BiHome/></a>
            <a href='#about' onClick={() => setActiveNav('#about')} className={activeNav === '#about'? 'active': ''}><AiOutlineUser/></a>
            <a href='#experience' onClick={() => setActiveNav('#experience')} className={activeNav === '#experience'? 'active': ''}><MdWorkOutline/></a>
            <a href='#portfolio' onClick={() => setActiveNav('#portfolio')} className={activeNav === '#portfolio'? 'active': ''}><AiOutlineCode/></a>
            <a href='#contact' onClick={() => setActiveNav('#contact')} className={activeNav === '#contact'? 'active': ''}><BiMessageSquareDetail/></a>
            </nav>
    )
}

As you can see, it has links to the other components. I have styled it as a floating navbar. When the user clicks on a link, they're taken to that section of the page. The link's class is changed to "active" - its CSS gets changed to distinguish it from the rest.

Now I want to do it the other way around. When a user scrolls to a component, say Experience, I want the class of the corresponding link in Nav to be changed to active. How can I do that?

Thanks very much for reading until the end :)

CodePudding user response:

maybe you can use onScroll event to calculate the difference between component's height and page's scrollTop in real time

CodePudding user response:

Maybe use the useEffect hook to listen for changes in the scroll position of the page and then updating the state of the activeNav based on the position of the different sections of the page

import { useEffect } from 'react';

const Nav = () => {
    const [activeNav, setActiveNav] = useState('#');

    useEffect(() => {
        const handleScroll = () => {
            const aboutSection = document.querySelector('#about');
            const experienceSection = document.querySelector('#experience');
            const portfolioSection = document.querySelector('#portfolio');
            const contactSection = document.querySelector('#contact');

            if (aboutSection.getBoundingClientRect().top < window.innerHeight * 0.8 && aboutSection.getBoundingClientRect().top > 0) {
                setActiveNav('#about');
            } else if (experienceSection.getBoundingClientRect().top < window.innerHeight * 0.8 && experienceSection.getBoundingClientRect().top > 0) {
                setActiveNav('#experience');
            } else if (portfolioSection.getBoundingClientRect().top < window.innerHeight * 0.8 && portfolioSection.getBoundingClientRect().top > 0) {
                setActiveNav('#portfolio');
            } else if (contactSection.getBoundingClientRect().top < window.innerHeight * 0.8 && contactSection.getBoundingClientRect().top > 0) {
                setActiveNav('#contact');
            }
        };

        window.addEventListener('scroll', handleScroll);

        return () => {
            window.removeEventListener('scroll', handleScroll);
        };
    }, [setActiveNav]);

    return (
        <nav>
            <a href='#' onClick={() => setActiveNav('#')} className={activeNav === '#'? 'active': ''}><BiHome/></a>
            <a href='#about' onClick={() => setActiveNav('#about')} className={activeNav === '#about'? 'active': ''}><AiOutlineUser/></a>
            <a href='#experience' onClick={() => setActiveNav('#experience')} className={activeNav === '#experience'? 'active': ''}><MdWorkOutline/></a>
            <a href='#portfolio' onClick={() => setActiveNav('#portfolio')} className={activeNav === '#portfolio'? 'active': ''}><AiOutlineCode/></a>
            <a href='#contact' onClick={() => setActiveNav('#contact')} className={activeNav === '#contact'? 'active': ''}><BiMessageSquareDetail/></a>
        </nav>
    )
}
  • Related