反应上下文 api 状态不会持续合成 onwheel 事件

问题描述

我正在尝试为轮播实现 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 删除一次 debouncedelayedScroll 吗?如果它有效,将以正确的方式引入去抖动逻辑。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...