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">; <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>; {topMovies && topMovies.map((電影) => ( <li className="carousel_slide"> >
{電影.標題}
</li> ))} </ul>
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>