首页 > 解决方案 > 车轮事件触发多次反应

问题描述

我正在尝试实现整页滚动。我的问题是车轮事件经常触发两次。我在 vanilla js 上实现了它,并且效果很好。

const [ index, setIndex ] = useState(0);
const sectionWrapper = useRef();
const animationBreak = 750;
const maxIndex = 2;
let lastTime = 0;

useEffect(
    () => {
        const handleWheel = e => {
            const sections = sectionWrapper.current.children;
            const wheelDirection = e.wheelDelta;
            const currentTime = new Date().getTime();
            const isAnimationEnable = currentTime - lastTime > animationBreak;

            if (!isAnimationEnable) return;

            if (wheelDirection < 0 && index < maxIndex) {
                setIndex(index + 1);
            }

            if (wheelDirection > 0 && index > 0) {
                setIndex(index - 1);
            }

            sections[index].scrollIntoView({ behavior: 'smooth' });
            lastTime = currentTime;
        };

        window.addEventListener('wheel', handleWheel);

        return () => window.removeEventListener('wheel', handleWheel);
    },
    [ index ]
);

我尝试使用 lodash 的方法,如油门或去抖动。不适合我。

标签: javascriptreactjsdom-eventsreact-hooksmousewheel

解决方案


您无需在每次索引更改时删除/重新分配事件处理程序,事件处理代码永远不会更改,您只需要访问最新index状态即可。您可以通过在函数上使用回调来做到这一点,setX例如

useEffect(() => {
  const handleWheel = e => {
    const sections = sectionWrapper.current.children;
    const wheelDirection = e.wheelDelta;
    const currentTime = new Date().getTime();
    const isAnimationEnable = currentTime - lastTime > animationBreak;

    if (!isAnimationEnable) return;

    let index;
    setIndex(i => index = i); // read most recent index
    // use a temp var to get the new state value for scrolling later
    let newIndex;
    if (wheelDirection < 0 && index < maxIndex) {
      setIndex(i => (newIndex = ++i)); // increment the current index by 1
    }

    if (wheelDirection > 0 && index > 0) {
      setIndex(i => (newIndex = --i)); // decrement the current index by 1
    }

    sections[newIndex].scrollIntoView({ behavior: 'smooth' });
    lastTime = currentTime;
  };

  window.addEventListener('wheel', handleWheel);

  return () => window.removeEventListener('wheel', handleWheel);
}, []); // we no longer need any dependences here

推荐阅读