How can I implement header animation on scroll up and down in React?

Viewed 168

I'm using this Codepen template and am trying to replicate this into React. I want to convert this jQuery code to React and am not sure how to do that:

$(window).scroll(function () {
  if ($(document).scrollTop() > 50) {
    $(".nav").addClass("affix");
    console.log("OK");
  } else {
    $(".nav").removeClass("affix");
  }
});

Here is what I have so far. I'm unsure how to make it so that when you scroll a certain amount, something happens, in this case the jQuery makes the CSS change:

import { useRef, useState } from "react";
import "./Navbar1.css";
import QueensLogoH from "./NavbarAssets/queens-logo-horizontal.png";

export default function App() {
  const [isActive, setIsActive] = useState(false);
  const mainListDivRef = useRef(null);

  function onClickNavTrigger() {
    setIsActive((a) => !a);
    const mainListDivEl = mainListDivRef.current;
    mainListDivEl.classList.toggle("show_list");
  }

  return (
    <>
      <nav className="nav">
        <div className="container">
          <div className="logo">
            <a href="#">
              <img src={QueensLogoH} height="80"></img>
            </a>
          </div>
          <div id="mainListDiv" className="main_list" ref={mainListDivRef}>
            <ul className="navlinks">
              <li>
                <a href="#">About</a>
              </li>
              <li>
                <a href="#">Portfolio</a>
              </li>
              <li>
                <a href="#">Services</a>
              </li>
              <li>
                <a href="#">Contact</a>
              </li>
            </ul>
          </div>
          <span className={`navTrigger ${isActive ? "active" : ""}`} onClick={onClickNavTrigger}>
            <i></i>
            <i></i>
            <i></i>
          </span>
        </div>
      </nav>

      <section className="home"></section>
      <div style={{ height: "1000px" }}>
        {/* <!-- just to make scrolling effect possible --> */}
        <h2 className="myH2">What is this ?</h2>
        <p className="myP">This is a responsive fixed navbar animated on scroll</p>
        <p className="myP">
          I took inspiration from ABDO STEIF (
          <a href="https://codepen.io/abdosteif/pen/bRoyMb?editors=1100">
            https://codepen.io/abdosteif/pen/bRoyMb?editors=1100
          </a>
          ) and Dicson{" "}
          <a href="https://codepen.io/dicson/pen/waKPgQ">(https://codepen.io/dicson/pen/waKPgQ)</a>
        </p>
        <p className="myP">I HOPE YOU FIND THIS USEFULL</p>
        <p className="myP">Albi</p>
        <p className="myP">random text</p>
      </div>
    </>
  );
}
1 Answers

You can use a scrolled state and useEffect where you write inside its callback the JS code that corresponds to what you have with jQuery.

The difference is that you would call setScrolled() with true or false and use scrolled to add conditionally the class affix to your nav. Like so:

import { useEffect, useRef, useState } from "react";
import "./Navbar1.css";
import QueensLogoH from "./NavbarAssets/queens-logo-horizontal.png";

export default function App() {
  const [isActive, setIsActive] = useState(false);
  const [scrolled, setScrolled] = useState(false);
  const mainListDivRef = useRef(null);

  function onClickNavTrigger() {
    setIsActive((a) => !a);
    const mainListDivEl = mainListDivRef.current;
    mainListDivEl.classList.toggle("show_list");
  }

  useEffect(() => {
    const listenToScroll = () => {
      if (window.pageYOffset > 50) {
        setScrolled(true);
      } else {
        setScrolled(false);
      }
    };
    window.addEventListener("scroll", listenToScroll);
    return () => window.removeEventListener("scroll", listenToScroll);
  }, []);

  return (
    <>
      <nav className={"nav " + (scrolled ? "affix" : "")}>
        <div className="container">
          <div className="logo">
            <a href="#">
              <img src={QueensLogoH} height="80"></img>
            </a>
          </div>
          <div id="mainListDiv" className="main_list" ref={mainListDivRef}>
            <ul className="navlinks">
              <li>
                <a href="#">About</a>
              </li>
              <li>
                <a href="#">Portfolio</a>
              </li>
              <li>
                <a href="#">Services</a>
              </li>
              <li>
                <a href="#">Contact</a>
              </li>
            </ul>
          </div>
          <span className={`navTrigger ${isActive ? "active" : ""}`} onClick={onClickNavTrigger}>
            <i></i>
            <i></i>
            <i></i>
          </span>
        </div>
      </nav>

      <section className="home"></section>
      <div style={{ height: "1000px" }}>
        {/* <!-- just to make scrolling effect possible --> */}
        <h2 className="myH2">What is this ?</h2>
        <p className="myP">This is a responsive fixed navbar animated on scroll</p>
        <p className="myP">
          I took inspiration from ABDO STEIF (
          <a href="https://codepen.io/abdosteif/pen/bRoyMb?editors=1100">
            https://codepen.io/abdosteif/pen/bRoyMb?editors=1100
          </a>
          ) and Dicson{" "}
          <a href="https://codepen.io/dicson/pen/waKPgQ">(https://codepen.io/dicson/pen/waKPgQ)</a>
        </p>
        <p className="myP">I HOPE YOU FIND THIS USEFULL</p>
        <p className="myP">Albi</p>
        <p className="myP">random text</p>
      </div>
    </>
  );
}

Notice that we might call setScrolled(true) multiple time while the user is scrolling down, but since React won't re-render if you give the same value to a state setter, it's not a problem here.

Related