我在使用以下組合時遇到了非常奇怪的閃爍(毛刺)
css滾動捕捉 使用狀態 子組件 但只有在這三者結合的情況下!
下面是最小可復制代碼:
carousel.js
import styles from './carousel.module.scss'
import { useEffect, useRef, useState } from 'react';
export default function Carousel() {
const [currentScollPos, setCurrentScrollPos] = useState(0)
const carouselRef = useRef()
useEffect(() => {
const carouselScrollUpdate = (e) => {
setCurrentScrollPos(e.target.scrollLeft)
}
carouselRef?.current?.addEventListener('scroll', carouselScrollUpdate, { passive: true })
return () => {
carouselRef?.current?.removeEventListener('scroll', carouselScrollUpdate, { passive: true })
}
}, [carouselRef])
const Slide = () => <div className={styles.carouselSlide}>Test Sub</div>
return (
<div className={styles.carouselInnerContainer} ref={carouselRef}>
<div className={styles.carouselSlide}>Test1</div>
<div className={styles.carouselSlide}>Test2</div>
<div className={styles.carouselSlide}>Test3</div>
<Slide />
</div>
)
}
轉盤.模塊. scss
.carouselInnerContainer {
display: flex;
flex-wrap: nowrap;
overflow-x: scroll;
scroll-snap-type: x mandatory;
}
.carouselSlide {
flex: 0 0 auto;
width: 50%;
margin-left: 2rem;
background-color: aquamarine;
height: 200px;
scroll-snap-align: center;
}
如果我執行以下操作之一,閃爍將不會出現:
注釋掉:setCurrentScrollPos(e . target . scroll left) 注釋掉:& ltslide/>; 注釋掉:滾動-對齊-對齊:居中;在CSS中 對這種奇怪的行為有什么想法嗎?
當您嘗試在每次滾動位置更改時更新狀態時,會出現此問題
const carouselScrollUpdate = (e) => {
setCurrentScrollPos(e.target.scrollLeft)
}
每個setCurrentScrollPos都會在你的組件中產生一個渲染器,導致它閃爍
相反,在每次可以觀察到滾動停止時,使用setTimout設置狀態:
const carouselScrollUpdate = (e) => {
clearInterval(timer);
timer = setTimeout(() => {
console.log('set scroll')
setCurrentScrollPos(e.target.scrollLeft)
}, 500);
}
或者只在滿足某些條件時設置狀態:
const carouselScrollUpdate = (e) => {
if (isNearNextSlide()) {
setCurrentScrollPos(e.target.scrollLeft)
}
}
const isNearNextSlide = () => {
// add logic to satisfy your conditions
}
編輯:
經過一些測試后,我發現問題出在內部的滑動組件,我設法通過將組件移出主組件來修復它,防止組件在渲染時被重新創建
import styles from './carousel.module.scss'
import { useEffect, useRef, useState } from 'react';
const Slide = () => <div className={styles.carouselSlide}>Test Sub</div>
export default function Carousel() {
const [currentScollPos, setCurrentScrollPos] = useState(0)
const carouselRef = useRef()
useEffect(() => {
const carouselScrollUpdate = (e) => {
setCurrentScrollPos(e.target.scrollLeft)
}
carouselRef?.current?.addEventListener('scroll', carouselScrollUpdate, { passive: true })
return () => {
carouselRef?.current?.removeEventListener('scroll', carouselScrollUpdate, { passive: true })
}
}, [carouselRef])
return (
<div className={styles.carouselInnerContainer} ref={carouselRef}>
<div className={styles.carouselSlide}>Test1</div>
<div className={styles.carouselSlide}>Test2</div>
<div className={styles.carouselSlide}>Test3</div>
<Slide />
</div>
)
}