I am creating a navigation bar with React that visually highlights the active component when it is scrolled into view by the user. So, they scroll to the 'About' component and the user icon would highlight and the home icon would return to normal. It looks like this:

I am trying to do this in 2 steps: (1) using the useInView hook in my App.jsx component to set the 'activeElement' with a useState hook when the user scrolls to the useInView {ref}, and (2) passing the 'activeElement' as a useState variable to the child Nav component via props and useEffect to update activeNav in the Nav component when the user is scrolling.
Here is my code for the App component, which I have been testing within the paragraph tags. Currently, activeElement is not being affected by scrolling.
const App = () => {
const { ref, inView, entry } = useInView({
/* Optional options */
threshold: 0,
});
const [activeElement, setActiveElement] = useState('#')
return (
<>
<Header ref={ref} setActiveElement={inView ? '#home' : '' }/>
<Nav activeElement={activeElement}/>
<About ref={ref} setActiveElement={inView ? '#about' : '' } />
<p>{activeElement}</p>
<Services ref={ref} setActiveElement={inView ? '#services' : '' } />
<Contact ref={ref} setActiveElement={inView ? '#contact' : '' }/>
<Footer />
<p>{activeElement}</p>
</>
)
}
export default App
And here is the code for my Nav component:
const Nav = ({activeElement}) => {
const [activeNav, setActiveNav] = useState('#');
useEffect(() => {
setActiveNav(activeElement);
})
return (
<nav>
<a href="#" onClick={() => setActiveNav('#')} className={activeNav === '#' ? 'active' : ''}><AiOutlineHome /></a>
<a href="#about" onClick={() => setActiveNav('#about')} className={activeNav === '#about' ? 'active' : ''}><AiOutlineUser /></a>
<a href="#experience" onClick={() => setActiveNav('#experience')} className={activeNav === '#experience' ? 'active' : ''}><HiOutlineBookOpen /></a>
<a href="#services" onClick={() => setActiveNav('#services')} className={activeNav === '#services' ? 'active' : ''}><FaUncharted /></a>
<a href="#contact" onClick={() => setActiveNav('#contact')} className={activeNav === '#contact' ? 'active' : ''}><RiMessage2Line /></a>
</nav>
)
}
export default Nav
What is wrong with my useInView execution? And am I passing the activeElement variable to the Nav component correctly?
Thanks for taking the time to read this through.
** SOLUTION: **
After some digging, and with thanks to the commenter, Ali Mirzaei, for helping to identify where the issue was occuring, we found 2 problems:
Working code is as follows:
const App = () => {
const { ref, inView } = useInView();
const { ref: ref1, inView: inView1 } = useInView();
const { ref: ref2, inView: inView2 } = useInView();
const { ref: ref3, inView: inView3 } = useInView();
const { ref: ref4, inView: inView4 } = useInView();
const [activeElement, setActiveElement] = useState('#')
useEffect(() => {
if (inView) {
setActiveElement('#home');
console.log('home');
};
if (inView1) {
setActiveElement('#about')
console.log('about');
};
if (inView2) {
setActiveElement('#experience')
console.log('experience');
};
if (inView3) {
setActiveElement('#services')
console.log('services');
};
if (inView4) {
setActiveElement('#contact')
console.log('contact');
};
}, [inView, inView1, inView2, inView3, inView4])
return (
<>
<Header innerRef={ref} />
<Nav activeElement={activeElement}/>
<About innerRef={ref1} />
<p>{activeElement} {inView.toString()}</p>
<Experience innerRef={ref2} />
<Services innerRef={ref3} />
<Contact innerRef={ref4} />
<Footer />
<p>{activeElement}</p>
</>
)
}
export default App
And for the Nav component:
const Nav = ({activeElement}) => {
const [activeNav, setActiveNav] = useState('#home');
useEffect(() => {
setActiveNav(activeElement);
})
return (
<nav>
<a href="#" onClick={() => setActiveNav('#home')} className={activeNav === '#home' ? 'active' : ''}><AiOutlineHome /></a>
<a href="#about" onClick={() => setActiveNav('#about')} className={activeNav === '#about' ? 'active' : ''}><AiOutlineUser /></a>
<a href="#experience" onClick={() => setActiveNav('#experience')} className={activeNav === '#experience' ? 'active' : ''}><HiOutlineBookOpen /></a>
<a href="#services" onClick={() => setActiveNav('#services')} className={activeNav === '#services' ? 'active' : ''}><FaUncharted /></a>
<a href="#contact" onClick={() => setActiveNav('#contact')} className={activeNav === '#contact' ? 'active' : ''}><RiMessage2Line /></a>
</nav>
)
}
export default Nav
And here is an example of the innerRef use from a component:
const About = ({ innerRef }) => {
return (
<section id='about'>
<div ref={innerRef}>
About
</div>
</section>
)
}
Hope that helps anyone out there experiencing the same issue!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With