车轮事件触发多次反应
Wheel event triggers many times react
我正在尝试实现整页滚动。我的问题是 wheel 事件经常触发两次。
我在 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 的方法,例如 throttle 或 debounce。不适合我。
您不需要在每次索引更改时删除/重新分配事件处理程序,事件处理代码永远不会更改,您只需要访问最近的 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
useRef 以更简洁的方式解决了这个问题。
const [ index, setIndex ] = useState(0);
// using useRef to ref to index
const indexRef = useRef();
indexRef.current = index;
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 && indexRef.current < maxIndex) {
setIndex(() => indexRef.current + 1);
sections[indexRef.current].scrollIntoView({ behavior: 'smooth' });
}
if (wheelDirection > 0 && indexRef.current > 0) {
setIndex(() => indexRef.current - 1);
sections[indexRef.current].scrollIntoView({ behavior: 'smooth' });
}
lastTime = currentTime;
};
window.addEventListener('wheel', handleWheel);
return () => window.removeEventListener('wheel', handleWheel);
}, []);
我正在尝试实现整页滚动。我的问题是 wheel 事件经常触发两次。 我在 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 的方法,例如 throttle 或 debounce。不适合我。
您不需要在每次索引更改时删除/重新分配事件处理程序,事件处理代码永远不会更改,您只需要访问最近的 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
useRef 以更简洁的方式解决了这个问题。
const [ index, setIndex ] = useState(0);
// using useRef to ref to index
const indexRef = useRef();
indexRef.current = index;
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 && indexRef.current < maxIndex) {
setIndex(() => indexRef.current + 1);
sections[indexRef.current].scrollIntoView({ behavior: 'smooth' });
}
if (wheelDirection > 0 && indexRef.current > 0) {
setIndex(() => indexRef.current - 1);
sections[indexRef.current].scrollIntoView({ behavior: 'smooth' });
}
lastTime = currentTime;
};
window.addEventListener('wheel', handleWheel);
return () => window.removeEventListener('wheel', handleWheel);
}, []);