反应上下文 api 状态不会持续用于合成 onwheel 事件
react context api state not persisting for synthetic onwheel event
我正在尝试为旋转木马实施 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
console log on wheel事件(长度不打印):
carouselPosition 0
感谢 kumarmo2,我通过删除去抖动并直接调用事件解决了这个问题。我用计时器做了一个非常老套的去抖动,专门针对车轮事件。
我的解决方案:
const ScrollNav = ({ children }) => {
const [, { nextSlide, 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 而更新,所以你遇到了这个问题。
您可以尝试为 delayedScroll
删除一次 useCallback
和 debounce
吗?如果有效,将以正确的方式引入去抖动逻辑。
我正在尝试为旋转木马实施 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
console log on wheel事件(长度不打印):
carouselPosition 0
感谢 kumarmo2,我通过删除去抖动并直接调用事件解决了这个问题。我用计时器做了一个非常老套的去抖动,专门针对车轮事件。 我的解决方案:
const ScrollNav = ({ children }) => {
const [, { nextSlide, 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 而更新,所以你遇到了这个问题。
您可以尝试为 delayedScroll
删除一次 useCallback
和 debounce
吗?如果有效,将以正确的方式引入去抖动逻辑。