Maison  >  Questions et réponses  >  le corps du texte

Il semble que useEffect soit déclenché même si l'état de dépendance n'a pas changé ?

<p>J'essaie de créer un composant carrousel dans mon projet React - j'essaie en fait d'exploiter un composant carrousel existant écrit en pur JS, en utilisant Refs pour le faire fonctionner dans React, plutôt que de le modifier directement DOM. Je rencontre un problème lorsque j'essaie d'initialiser le carrousel en marquant la première diapositive de la séquence comme diapositive actuelle (avec className current-slide). J'ai mis cette action dans un hook useEffect où {topMovies} est une dépendance. {topMovies} est un tableau d'objets transmis au composant carrousel via prop, donc lorsque topMovies change (c'est-à-dire se charge), useEffect doit s'exécuter. Cela fonctionne - après le chargement, la première diapositive du carrousel reçoit le nom de classe « diapositive actuelle ». </p> <p>Cependant, le deuxième morceau de code (nextSlide et moveToSlide) est le début de la fonction qui sélectionne la diapositive suivante. Transmettez la référence de piste (c'est-à-dire le conteneur de toutes les diapositives) à la fonction afin que l'élément enfant avec le nom de classe 'current-slide' puisse être sélectionné et son nom de classe supprimé. Cela fonctionne également - mais après un court délai (~ 1 seconde), le nom de classe 'current-slide' réapparaît.</p> <pre class="brush:php;toolbar:false;">const Carouselv2 = ({topMovies}) => { //Réfs const trackRef = useRef(); const nextBtnRef = useRef(); const prevBtnRef = useRef(); const navDotsRef = useRef(); //Initialiser le carrousel lors du chargement de l'hélice const [isLoading, setIsLoading] = useState(true); useEffect(() => { if (topMovies && setIsLoading) { const slides = Array.from(trackRef.current.children); slides[0].classList.add('current-slide'); //Marquer la première diapositive comme visible const slideWidth = slides[0].getBoundingClientRect().width; const setSlidePosition = (diapositive, index) => { slide.style.left = slideWidth * index + 'px'; } slides.forEach(setSlidePosition); // Disposer les diapositives les unes à côté des autres setIsLoading(faux); } }, [meilleurs films]); //Fonctionnalité des boutons const moveToSlide = (currentSlide, targetSlide) => { //trackRef.current.style.transform = 'translateX(-' + targetSlide.style.left + ')'; currentSlide.classList.remove('current-slide'); //targetSlide.classList.add('current-slide'); } const updateDots = () => { } const responsiveBtns = () => { } const prevSlide = (e) => { } const nextSlide = (e) => { const currentSlide = trackRef.current.querySelector('.current-slide'); const nextSlide = trackRef.current.children.nextElementSibling; moveToSlide(currentSlide, nextSlide); } retour ( <div className="carrousel"> <button className="carousel_button carousel_button--left" ref={prevBtnRef}><FontAwesomeIcon icon={faCircleLeft} size="xl" style={{ color: "white" }} /></button> ; <div className="carousel_track-container"> <ul className="carousel_track" ref={trackRef}> {topFilms && topMovies.map((film) => ( <li className="carousel_slide"> <img src={movie.image} alt="" /> <h2>{movie.title}</h2> ≪/li> ))} </ul> </div> <button onClick={(e) => nextSlide(e)}className="carousel_button carousel_button--right" ref={nextBtnRef}><FontAwesomeIcon icon={faCircleRight} size="xl" style={{ couleur : "blanc" }} /></bouton> <div className="carousel_nav" ref={navDotsRef}> <button className="carousel_indicator current-slide"></button> {topMovies && Array.apply(0, Array(topMovies.length)).map(() => { return <button className="carousel_indicator"></button> })} </div> </div> ); }</pré> <p>Ma pensée initiale était que, pour une raison quelconque, la modification de className provoquait le déclenchement de useEffect, j'ai donc ajouté une instruction if avec une condition isLoading. Mais cela n'a pas fonctionné, donc je ne pense pas que le bug vienne du hook useEffect. </p> <p>Très confus par cela, mais c'est la première fois que j'utilise Refs, il est donc tout à fait possible que je manque quelque chose de très évident. Merci pour votre aide! </p>
P粉946336138P粉946336138403 Il y a quelques jours475

répondre à tous(1)je répondrai

  • P粉642436282

    P粉6424362822023-08-16 10:19:47

    Vous mélangez du DOM créé à l'aide de React et du DOM manipulé à l'aide de Javascript pur. Vous ne pouvez pas faire cela, cela romprait simplement la relation DOM/VDOM.

    Si vous souhaitez éviter de déplacer l'ensemble du composant pour qu'il fonctionne comme le fait React, utilisez simplement Ref sur un élément vide, l'avantage est que vous bénéficiez des avantages du montage et du démontage des composants.

    Ensuite, vous pouvez copier-coller le code Javascript et simplement tout mettre à l'intérieur useEffect.

    Par exemple :

    Ci-dessous, j'ai créé deux boutons, l'un entièrement contrôlé par React et l'autre par JS, qui feront simplement basculer la classe pink-button lorsque vous cliquerez dessus. J'ai également placé une case à cocher pour inverser l'ordre des boutons afin de provoquer un nouveau rendu montrant que l'état de la version JS n'a pas été détruit, assurez-vous d'utiliser l'attribut key lors de cette opération pour faire savoir à React qu'il s'agit du même composant. L'essentiel ici est de montrer que React n'interférera désormais plus avec ce bouton, c'est désormais entièrement votre responsabilité. J'espère que cela vous aidera à comprendre comment mélanger React avec du JS pur.

    const domContainer = document.querySelector('#mount');
    const root = ReactDOM.createRoot(domContainer);
    
    const {createRef, useEffect, useState} = React;
    
    function JSButton() {
      const btnRef = createRef(); 
      useEffect(() => {
         //do everything now from inside this useEffect
         const btn = btnRef.current;     
         btn.innerText = 'This is a Javascript Button';     
         const doClick = () => btn.classList.toggle('pink-button');
         btn.addEventListener('click', doClick);     
         return () => {
           //we can also do any clean-up here
           btn.removeEventListner('click', doClick);
         }
      }, []);
      //only render the button component,
      //don't add any props, classes etc.
      //our JS will be handling it all.
      return <button ref={btnRef}/>;
    }
    
    function ReactButton() {
      const [pink, setPink] = useState(false);
      return <button 
        onClick={() => setPink(p => !p)}
        className={pink ? 'pink-button' : ''}>
        React Button
      </button>;
    }
    
    function Test() {
      const [jsFirst, setJsFirst] = useState(false);
      return <React.Fragment>
         <input type="checkbox"
           checked={jsFirst}
           onChange={(e) => {
             setJsFirst(e.target.checked);
           }}
         />Js First
         {jsFirst 
           ? <React.Fragment>
               <JSButton key={'js'}/>
               <ReactButton key={'r'}/>
             </React.Fragment>
           : <React.Fragment>
               <ReactButton key={'r'}/>
               <JSButton key={'js'}/>
             </React.Fragment>       
         }
      </React.Fragment>
    }
    
    root.render(<Test/>);
    .pink-button {
      background-color: pink;
    }
    
    button {
      display: block;
      width: 200px;
      margin: 1rem;
    }
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    
    <div id="mount"></div>

    répondre
    0
  • Annulerrépondre