搜尋

首頁  >  問答  >  主體

似乎觸發了useEffect,即使依賴狀態未改變?

<p>我正在嘗試在我的React專案中建立一個輪播元件- 實際上,我試圖利用一個用純JS編寫的現有輪播元件,使用Refs在React中使其工作,而不是直接修改DOM。當我嘗試將序列中的第一張投影片標記為目前投影片(具有className current-slide)來初始化輪播時,我遇到了問題。我將此操作放在了一個useEffect鉤子中,其中{topMovies}是依賴項。 {topMovies}是一個透過prop傳遞給輪播元件的物件數組,因此當topMovies發生變化(即載入)時,useEffect應該會運作。這個動作是有效的 - 載入後,輪播中的第一張投影片被賦予了classname 'current-slide'。 </p> <p>然而,第二段程式碼(nextSlide和moveToSlide)是選擇下一張投影片的函數的開始。將track Ref(即所有投影片的容器)傳遞給函數,以便可以選擇具有className 'current-slide'的子元素,並刪除其className。這也是有效的 - 但是在短暫的延遲(約1秒)後,className 'current-slide'重新出現。</p>
const Carouselv2 = ({topMovies}) =>; {

    //引用

    const trackRef = useRef();
    const nextBtnRef = useRef();
    const prevBtnRef = useRef();
    const navDotsRef = useRef();

    //在道具載入時初始化輪播

    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        if (topMovies && setIsLoading) {
            const Slides = Array.from(trackRef.current.children);

            Slides[0].classList.add('目前投影片'); //將第一張投影片標記為可見

            const SlideWidth = Slides[0].getBoundingClientRect().width;

            const setSlidePosition = (幻燈片, 索引) => {
                Slide.style.left = SlideWidth * 索引 'px';
            }

            幻燈片.forEach(setSlidePosition); //將幻燈片並排排列

            setIsLoading(假);
        }
    }, [熱門電影]);

    //按鈕功能

    const moveToSlide = (currentSlide, targetSlide) =>; {
        //trackRef.current.style.transform = 'translateX(-' targetSlide.style.left ')';
        currentSlide.classList.remove('目前投影片');
        //targetSlide.classList.add('目前投影片');
    }

    const updateDots = () =>; {

    }

    constresponsiveBtns = () =>; {

    }

    const prevSlide = (e) =>; {

    }

    const nextSlide = (e) =>; {
        const currentSlide = trackRef.current.querySelector('.current-slide');
        const nextSlide = trackRef.current.children.nextElementSibling;

        moveToSlide(目前投影片, 下一個投影片);
    }

    返回 (
        
<按鈕 className="carousel_button carousel_button--left" ref={prevBtnRef}><FontAwesomeIcon icon={faCircleLeft} size="xl" style={{ color: "white" }} /> ; <div className="carousel_track-container">
    ; {topMovies && topMovies.map((電影) => ( <li className="carousel_slide"> >

    {電影.標題}

    </li> ))} </ul>
; <button onClick={(e) => nextSlide(e)}className="carousel_button carousel_button--right" ref={nextBtnRef}><FontAwesomeIcon icon={faCircleRight} size=" color: "white" }} /></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>我最初的想法是由於某種原因,更改className導致useEffect觸發,因此我添加了帶有isLoading條件的if語句。但這並沒有起作用,所以我不認為bug來自於useEffect鉤子。 </p> <p>對此感到非常困惑,但這是我第一次使用Refs,所以完全有可能我錯過了一些非常明顯的東西。非常感謝您的幫忙! </p>
P粉946336138P粉946336138500 天前566

全部回覆(1)我來回復

  • P粉642436282

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

    您正在混合使用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>

    回覆
    0
  • 取消回覆