web-dev-qa-db-fra.com

Basculer la classe en fonction du défilement React JS

J'utilise bootstrap 4 barre de navigation et je voudrais changer la couleur d'arrière-plan après ig 400px bas défiler vers le bas. Je regardais les documents React et j'ai trouvé un onScroll mais je n'ai pas pu trouver grand-chose Jusqu'à présent, j'ai ...

Je ne sais pas si j'utilise le bon écouteur d'événement ou comment définir la hauteur, etc.

Et je ne mets pas vraiment de styles en ligne ...

  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;
13
Fernando B

Une façon d'ajouter un écouteur de défilement consiste à utiliser la méthode de cycle de vie componentDidMount(). L'exemple suivant devrait vous donner une idée:

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'));

Cela change le texte de "Défilement vers le bas" à "Défilement vers le haut" lorsque votre position scrollY est à 100 et au-dessus.

Modifier: devrait éviter l'excès de mise à jour de l'état sur chaque parchemin. Ne le mettez à jour que lorsque la valeur booléenne change.

16
glennreyes

Pour ceux d'entre vous qui ont lu cette question en 2019 , j'ai pris la réponse @glennreyes et l'ai réécrite en utilisant React Hooks :

  const [scroll, setScroll] = useState(0)

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

Gardez à l'esprit que, useState a un tableau de deux éléments, tout d'abord l'objet d'état et d'autre part la fonction qui la met à jour .

Dans le même ordre d'idées, useEffect nous aide à remplacer componentDidmount , la fonction écrite actuellement ne fait aucun nettoyage car ce n'est pas nécessaire dans ce cas.

Si vous trouvez qu'il est essentiel de nettoyer, vous pouvez simplement retourner une fonction à l'intérieur de useEffect .

Vous pouvez lire en détail ici .

MISE À JOUR:

Si vous aviez envie de le rendre modulaire et même de faire le nettoyage , vous pouvez faire quelque chose comme ceci:

  1. Créez un crochet personnalisé comme ci-dessous;

    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. Appelez-le à l'intérieur de tout composant que vous trouvez:

    Const component = () => {
    
    // calling our custom hook
    const scroll = useScrollHandler()
    
    ....... rest of your code
    
    }
    
6
Pouya Ataei

C'est mieux

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

class App extends React.Component {
    constructor(props) {
    super(props);

    this.state = {
      isTop: true
    };
    this.onScroll = this.onScroll.bind(this);
  }

  componentDidMount() {
    document.addEventListener('scroll', () => {
      const isTop = window.scrollY < 100;
      if (isTop !== this.state.isTop) {
        this.onScroll(isTop);
      }
    });
  }

  onScroll(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'));
3
amirhossein693

J'ai changé un peu la réponse @PouyaAtaei pour mon cas d'utilisation.

 import { useState, useEffect } from "react"

// Added distance parameter to determine how much 
// from the top tell return value is updated.
// The name of the hook better reflects intended use.
export const useHasScrolled = (distance = 10) => {

// setting initial value to false
const [scroll, setScroll] = useState(false)

// running on mount
useEffect(() => {
  const onScroll = () => {
// Logic is false tell user reaches threshold, then true after.
     const scrollCheck = window.scrollY >= distance;
    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

}
};

Appeler le crochet:

Const component = () => {

// calling our custom hook and optional distance agument.
const scroll = useHasScrolled(250)

}
0
wildair

Ceci est encore une autre approche de prise/ma prise sur crochets pour l'affichage sur le défilement et le masquage d'un élément de page aléatoire.

Je me suis beaucoup inspiré de: le post de Dan Abramov ici .

Vous pouvez consulter un exemple de travail complet, dans cette démo CodeSandbox .

Voici le code du hook personnalisé useScroll:

import React, { useState, useEffect } from "react";

export const useScroll = callback => {
  const [scrollDirection, setScrollDirection] = useState(true);

  const handleScroll = () => {
    const direction = (() => {
      // if scroll is at top or at bottom return null,
      // so that it would be possible to catch and enforce a special behaviour in such a case.
      if (
        window.pageYOffset === 0 ||
        window.innerHeight + Math.ceil(window.pageYOffset) >=
          document.body.offsetHeight
      )
        return null;
      // otherwise return the direction of the scroll
      return scrollDirection < window.pageYOffset ? "down" : "up";
    })();

    callback(direction);
    setScrollDirection(window.pageYOffset);
  };

  // adding and cleanning up de event listener
  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  });
};

Et ce crochet sera consommé comme ceci:

  useScroll(direction => {
    setScrollDirection(direction);
  });

Un composant complet utilisant ce crochet personnalisé:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import CustomElement, { useScroll } from "./element";
import Scrollable from "./scrollable";

function Page() {
  const [scrollDirection, setScrollDirection] = useState(null);

  useScroll(direction => {
    setScrollDirection(direction);
  });

  return (
    <div>
      {/* a custom element that implements some scroll direction behaviour */}
      {/* "./element" exports useScroll hook and <CustomElement> */}
      <CustomElement scrollDirection={scrollDirection} />
      {/* just a lorem ipsum long text */}
      <Scrollable />
    </div>
  );
}

const rootElement = document.getElementById("root");

ReactDOM.render(<Page />, rootElement);

Et enfin le code de CustomElement:

import React, { useState, useEffect } from "react";

export default props => {
  const [elementVisible, setElementVisible] = useState(true);
  const { scrollDirection } = props;

  // when scroll direction changes element visibility adapts, but can do anything we want it to do
  // U can use ScrollDirection and implement some page shake effect while scrolling
  useEffect(() => {
    setElementVisible(
      scrollDirection === "down"
        ? false
        : scrollDirection === "up"
        ? true
        : true
    );
  }, [scrollDirection]);

  return (
    <div
      style={{
        background: "#ff0",
        padding: "20px",
        position: "fixed",
        width: "100%",
        display: `${elementVisible ? "inherit" : "none"}`
      }}
    >
      element
    </div>
  );
};
0
Sergiu Dogotaru