Construisez une barre de navigation collante avec React

Jan 23, 2020 6 min Follow me on Twitter

Subscribe to receive the free weekly article

Cet article a été mis à jour le 2020-10-27

Je suis sûr que vous avez déjà vu l'effet que nous allons faire aujourd'hui, c'est une animation courante que nous voyons sur beaucoup de sites Web. Lorsque l'utilisateur fait défiler, la barre de navigation se déplace vers le bas avec un effet d'animation cool.

Vous avez de la chance aujourd'hui car, dans cet article, nous reproduirons le même effet avec React en construisant une barre de navigation collante à partir de zéro avec un crochet personnalisé.

Vous pouvez le voir en direct ici

Mise en place du projet

Pour pouvoir suivre, vous devez créer une nouvelle application React en exécutant la commande suivante:

npx create-react-app react-sticky-navbar

Ensuite, structurez votre dossier comme suit.

src
├── App.js
├── App.test.js
├── assets
|  └── images
|     └── logo.svg
├── components
|  └── Header
|     ├── About.js
|     ├── Navbar.css
|     ├── Navbar.js
|     ├── Welcome.css
|     └── Welcome.js
├── hooks
|  └── useSticky.js
├── index.css
├── index.js
├── serviceWorker.js
└── setupTests.js

Je me concentrerai principalement sur les fichiers liés à la barre de navigation pour rendre ce post court et utile. Vous pouvez toujours trouver le code source à la fin de l'article.

Maintenant, il est temps de nous salir les mains en écrivant du code.

  • Header/Welcome.js
import React from "react"

import "./Welcome.css"
import Logo from "../../assets/images/logo.svg"
import About from "./About"

const Welcome = ({ element }) => {
  return (
    <main>
      <section className="welcome">
        <div ref={element}>
          <img src={Logo} alt="logo" className="welcome--logo" />
          <p>Even if you scroll, i will stick with you</p>
          <button className="welcome__cta-primary">Contact us</button>
        </div>
      </section>
      <About />
    </main>
  )
}

export default Welcome

Comme vous pouvez le voir, nous avons ici un composant simple qui reçoit le props element. Ce dernier est la référence de l'élément qui déclenchera l'effet collant plus tard lors du défilement.

Au passage, j'utilise ici la déstructuration pour extraire l'élément. Si vous le souhaitez aussi, vous pouvez utiliser props.stickyRef.

Passons maintenant au fichier suivant et créons le squelette de la barre de navigation.

  • Header/Navbar.js
import React from "react"
import "./Navbar.css"
import Logo from "../../assets/images/logo.svg"

const Navbar = () => (
  <nav className="navbar">
    <div className="navbar--logo-holder">
      <img src={Logo} alt="logo" className="navbar--logo" />
      <h1> Stick'Me</h1>
    </div>
    <ul className="navbar--link">
      <li className="navbar--link-item">Home</li>
      <li className="navbar--link-item">About</li>
      <li className="navbar--link-item">Blog</li>
    </ul>
  </nav>
)
export default Navbar

Ici, nous avons pour l'instant un composant très simple. Mais plus tard, nous le mettrons à jour pour pouvoir afficher certains éléments de manière conditionnelle. Et aussi rendre la barre de navigation collante.

L'effet collant

Pour l'effet collant, nous allons créer un hook personnalisé pour gérer l'effet, puis l'utiliser dans notre composant et en même temps, le rendre réutilisable.

  • hooks/useSticky.js
import { useEffect, useState, useRef } from "react"

function useSticky() {
  const [isSticky, setSticky] = useState(false)
  const element = useRef(null)

  const handleScroll = () => {
    window.scrollY > element.current.getBoundingClientRect().bottom
      ? setSticky(true)
      : setSticky(false)
  }

  // This function handle the scroll performance issue
  const debounce = (func, wait = 20, immediate = true) => {
    let timeOut
    return () => {
      let context = this,
        args = arguments
      const later = () => {
        timeOut = null
        if (!immediate) func.apply(context, args)
      }
      const callNow = immediate && !timeOut
      clearTimeout(timeOut)
      timeOut = setTimeout(later, wait)
      if (callNow) func.apply(context, args)
    }
  }

  useEffect(() => {
    window.addEventListener("scroll", debounce(handleScroll))
    return () => {
      window.removeEventListener("scroll", () => handleScroll)
    }
  }, [debounce, handleScroll])

  return { isSticky, element }
}

export default useSticky

Toute la magie se produira ici (je le promets). Nous devons d'abord importer quelques hooks de React. Et ensuite, définir notre état avec useState() et définir l'état initial à false. Cela signifie que, maintenant, nous pourrons basculer entre true et false selon le défilement.

Lorsque l'utilisateur commence à faire défiler, la fonction handleScroll() sera appelé. Et, il vérifie si window.scrollY> stickyRef.current.getBoundingClientRect(). Bottom et gère l'état de isSticky. En d'autres termes, il vérifiera si le nombre de pixels que la page a actuellement défilé le long de l'axe vertical est supérieur ou non à la position de l'élément actuel par rapport à son bas.

Ensuite, nous utilisons une fonction anti-rebond pour limiter l'événement de défilement et éviter les problèmes de performances. Cette fonction, au lieu d'exécuter handleScroll tout le temps, s'exécutera toutes les 20 millisecondes pour vous donner plus de contrôle.

Avec cela, nous pouvons maintenant écouter l'événement de défilement lorsque le composant est monté et supprimer les écouteurs lorsqu'il est démonté.

Génial! maintenant pour rendre notre crochet personnalisé utilisable dans d'autres fichiers, nous devons en renvoyer quelque chose. Ici, nous devons retourner l'état isSticky etelement qui permet d'avoir une référence d'élément.

  • Header/Navbar.js
import React from "react"
import "./Navbar.css"
import Logo from "../../assets/images/logo.svg"

const Navbar = ({ sticky }) => (
  <nav className={sticky ? "navbar navbar-sticky" : "navbar"}>
    <div className="navbar--logo-holder">
      {sticky ? <img src={Logo} alt="logo" className="navbar--logo" /> : null}
      <h1> Stick'Me</h1>
    </div>
    <ul className="navbar--link">
      <li className="navbar--link-item">Home</li>
      <li className="navbar--link-item">About</li>
      <li className="navbar--link-item">Blog</li>
    </ul>
  </nav>
)
export default Navbar

Comme vous pouvez le voir, ce fichier reçoit maintenant comme props l'état collant. Nous pouvons maintenant vérifier si c'est true ou false et afficher les classes ou les éléments de manière conditionnelle à l'aide de l'opérateur ternaire.

Nous avons beaucoup couvert, cependant, il reste une partie importante: le style et les animations. Faisons-le dans la section suivante.

Styliser la barre de navigation

  • In Navbar.css
.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 2.5rem;
  position: absolute;
  z-index: 1;
  width: 100%;
}

.navbar-sticky {
  background: #333;
  position: fixed;
  top: 0;
  left: 0;
  box-shadow: 1px 1px 1px #222;
  animation: moveDown 0.5s ease-in-out;
}

.navbar--logo {
  width: 2rem;
  height: 2rem;
  margin-right: 0.5rem;
  animation: rotate 0.7s ease-in-out 0.5s;
}

@keyframes moveDown {
  from {
    transform: translateY(-5rem);
  }
  to {
    transform: translateY(0rem);
  }
}

@keyframes rotate {
  0% {
    transform: rotateY(360deg);
  }
  100% {
    transform: rotateY(0rem);
  }
}

Ici, en plus de fixer la barre de navigation sur le défilement avec la classe .navbar-sticky, nous utilisons moveDown pour faire l'effet d'animation qui fait également pivoter un peu le logo pour que tout paraisse bien et fluide lors du défilement.

Avec cela, nous pouvons maintenant utiliser le fichier App.js pour afficher nos composants lorsque la page se charge.

  • App.js
import React from "react"
import useSticky from "./hooks/useSticky.js"
import Welcome from "./components/Header/Welcome"
import Navbar from "./components/Header/Navbar"

function App() {
  const { isSticky, element } = useSticky()
  return (
    <>
      <Navbar sticky={isSticky} />
      <Welcome element={element} />
    </>
  )
}

export default App

Comme vous pouvez le voir, ici, nous importons nos composants et le hook personnalisé qui nous permet de transmettre des accessoires et de gérer l'effet collant de manière appropriée.

Avec cela, nous avons maintenant terminé la construction de notre barre de navigation collante à l'aide de React JS.

Merci de l'avoir lu.

Vous pouvez trouver le Code source ici

#react#hooks

Support my work

Get articles in your inbox