反应上下文 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 删除一次 useCallbackdebounce 吗?如果有效,将以正确的方式引入去抖动逻辑。