Es scheint, dass useEffect ausgelöst wird, obwohl sich der Abhängigkeitsstatus nicht geändert hat?
P粉946336138
P粉946336138 2023-08-15 16:21:30
0
1
555
<p>Ich versuche, eine Karussellkomponente in meinem React-Projekt zu erstellen – ich versuche tatsächlich, eine vorhandene, in reinem JS geschriebene Karussellkomponente zu nutzen, indem ich Refs verwende, damit sie in React funktioniert, anstatt sie direkt im DOM zu ändern. Ich stoße auf ein Problem, wenn ich versuche, das Karussell zu initialisieren, indem ich die erste Folie in der Sequenz als aktuelle Folie markiere (mit Klassenname current-slide). Ich habe diese Aktion in einen useEffect-Hook eingefügt, wobei {topMovies} eine Abhängigkeit ist. {topMovies} ist ein Array von Objekten, die über prop an die Karussellkomponente übergeben werden. Wenn sich topMovies also ändert (d. h. lädt), sollte useEffect ausgeführt werden. Das funktioniert – nach dem Laden erhält die erste Folie im Karussell den Klassennamen „current-slide“. </p> <p>Der zweite Codeabschnitt (nextSlide und moveToSlide) ist jedoch der Anfang der Funktion, die die nächste Folie auswählt. Übergeben Sie die Track-Referenz (d. h. den Container aller Folien) an die Funktion, damit das untergeordnete Element mit dem Klassennamen „current-slide“ ausgewählt und sein Klassenname entfernt werden kann. Das funktioniert auch – aber nach einer kurzen Verzögerung (~1 Sekunde) erscheint der Klassenname „current-slide“ wieder.</p> <pre class="brush:php;toolbar:false;">const Carouselv2 = ({topMovies}) => { //Ref const trackRef = useRef(); const nextBtnRef = useRef(); const prevBtnRef = useRef(); const navDotsRef = useRef(); //Karussell beim Laden der Stütze initialisieren const [isLoading, setIsLoading] = useState(true); useEffect(() => { if (topMovies && setIsLoading) { const slides = Array.from(trackRef.current.children); slides[0].classList.add('current-slide'); //Erste Folie als sichtbar markieren const slideWidth = slides[0].getBoundingClientRect().width; const setSlidePosition = (slide, index) => { slide.style.left = slideWidth * index + 'px'; } slides.forEach(setSlidePosition); //Folien nebeneinander anordnen setIsLoading(false); } }, [Top Filme]); //Button-Funktionalität 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); } zurückkehren ( <div className="carousel"> <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}> {topMovies && topMovies.map((movie) => ( <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={{ Farbe: „weiß“ }} /></button> <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> ); }</pre> <p>Mein erster Gedanke war, dass die Änderung von className aus irgendeinem Grund dazu führte, dass useEffect ausgelöst wurde, also fügte ich eine if-Anweisung mit einer isLoading-Bedingung hinzu. Aber das hat nicht funktioniert, daher glaube ich nicht, dass der Fehler vom useEffect-Hook herrührt. </p> <p>Das verwirrt mich sehr, aber ich verwende Refs zum ersten Mal, daher ist es durchaus möglich, dass ich etwas sehr Offensichtliches übersehe. Ich danke Ihnen für Ihre Hilfe! </p>
P粉946336138
P粉946336138

Antworte allen(1)
P粉642436282

您正在混合使用React创建的DOM和使用纯Javascript操作的DOM。您不能这样做,这只会破坏DOM / VDOM关系。

如果您想避免将整个组件移动以按照React的方式工作,那么只需在空元素上使用Ref,好处是您可以获得组件挂载和卸载的好处。

然后,您几乎可以复制粘贴Javascript代码,只需将其全部放在useEffect中即可。

例如:

下面我创建了两个按钮,一个完全由React控制,另一个由JS控制,当您点击它时,它只会切换pink-button类。 我还放置了一个复选框来翻转按钮的顺序以引起重新渲染,以展示JS版本的状态没有被破坏,请确保在这样做时使用key属性让React知道它是相同的组件。这里的主要观点是展示React现在将不再干预这个按钮,它现在完全由您负责。希望这能帮助您了解如何将React与纯JS混合使用。

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>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage