问题描述
我正在尝试为轮播实现 onWheel 触发的导航。按钮导航有效,而 onWheel 触发,但不知何故未访问上下文提供程序的初始化状态。任何见解将不胜感激。谢谢。
上下文提供者:
import CarouselContext from "../context/_carousel"
const CarouselProvider = ({ children }) => {
const [isInitialized,setIsInitialized] = useState(false)
const [carouselLength,setCarouselLength] = useState(0)
const [carouselPosition,setCarouselPosition] = useState(0)
const initializeCarousel = length => {
setCarouselLength(length)
setIsInitialized(true)
console.log(`carouselLength ${carouselLength}`)
}
const nextSlide = () => {
if (carouselPosition === carouselLength) {
setCarouselPosition(0)
} else {
setCarouselPosition(carouselPosition + 1)
}
console.log(`carouselPosition ${carouselPosition}`)
}
const prevIoUsSlide = () => {
if (carouselPosition === 0) {
setCarouselPosition(carouselLength)
} else {
setCarouselPosition(carouselPosition - 1)
}
console.log(`carouselPosition ${carouselPosition}`)
}
const state = { carouselLength,carouselPosition,isInitialized }
const methods = { initializeCarousel,nextSlide,prevIoUsSlide }
return (
<CarouselContext.Provider value={[state,methods]}>
{children}
</CarouselContext.Provider>
)
}
export default CarouselProvider
轮播结构:
return (
<Page className="works">
<CarouselProvider>
<ScrollNav>
<PrevIoUsWorkButton />
<Carousel>
{works.map((work,index) => (
<CarouselItem key={index}>
<Work project={work} />
</CarouselItem>
))}
</Carousel>
<NextWorkButton />
</ScrollNav>
</CarouselProvider>
</Page>
)
scroll Nav(安慰事件被触发,但不显示轮播的当前位置或长度)
const ScrollNav = ({ children }) => {
const [,{ nextSlide,prevIoUsSlide }] = useContext(CarouselContext)
const delayedScroll = useCallback(
debounce(e => changeNav(e),500,{ leading: true,trailing: false }),[]
)
const changeNav = direction => {
if (direction === 1) {
nextSlide()
}
if (direction === -1) {
prevIoUsSlide()
}
}
const onWheel = e => {
delayedScroll(e.deltaY)
}
return <div onWheel={onWheel}>{children}</div>
}
在轮播位置和长度持续的情况下触发相同事件的onclick按钮
const NextWorkButton = () => {
const [,{ nextSlide }] = useContext(CarouselContext)
const clicked = () => {
nextSlide()
}
return (
<div className="next-work-button">
<button onClick={clicked}>
<DownArrowSvg />
</button>
</div>
)
}
编辑以在提供程序中添加 console.logs,就像在我的本地副本中一样
控制台记录点击事件:
carouselPosition 1
carouselLength 5
控制台登录滚轮事件(长度不打印):
carouselPosition 0
感谢 kumarmo2,我通过删除去抖动并直接调用事件来解决这个问题。我做了一个非常hacky 的去抖动,专门针对带计时器的轮子事件。 我的解决方案:
const ScrollNav = ({ children }) => {
const [,prevIoUsSlide }] = useContext(CarouselContext)
const [debounce,setDebounce] = useState(false)
const timer = () => {
setTimeout(() => {
setDebounce(false)
},1000)
}
const changeNav = e => {
let direction = e.deltaY
if (debounce) {
return
} else if (direction >= 1) {
setDebounce(true)
timer()
nextSlide()
return
} else if (direction <= -1) {
setDebounce(true)
timer()
prevIoUsSlide()
return
}
}
return <div onWheel={changeNav}>{children}</div>
}
解决方法
我认为这里发生的情况是,您的 delayedScroll
由于 useCallback
没有得到更新。它“捕获”了 changeNav
,后者又捕获了 nextSlide
。
所以 nextSlide 将被调用,但由于它在 delayedScroll
中的引用没有因为 useCallback 而更新,您正面临这个问题。
您可以尝试为 useCallback
删除一次 debounce
和 delayedScroll
吗?如果它有效,将以正确的方式引入去抖动逻辑。