Итак, причина, по которой значение персонажа в вашей функции setEvent
всегда равно 0, заключается в том, что вокруг него есть замыкание, которое создается при первом монтировании компонента и запуске ловушки useEffect
.
Вот как я бы решил вашу проблему так же, как вы в настоящее время делаете:
Я переместил функции handleWheel и setEvent в функцию useEffect, чтобы указать, что их значения не меняются в течение срока действия эффекта. Я также избавился от ссылок на текущие значения persona, сделав так, чтобы вызовы setPersona не go выходили за их пределы.
export const Equipo = () => {
const container = useRef(null);
const [persona, setPersona] = useState(0);
useEffect(() => {
const handleWheel = (e) => {
e.stopPropagation();
setEvent(false);
if (Math.sign(e.deltaY) === -1) {
console.log('swipe DOWN');
setPersona((prevPers) => {
Math.max(0, prevPers - 1);
});
} else {
console.log('swipe UP');
setPersona((prevPers) => Math.min(team.length, prevPers + 1));
}
setTimeout(() => {
console.log('available to scroll');
setEvent(true);
}, 3000);
};
const setEvent = (status) => {
status === true
? container.current.addEventListener('wheel', handleWheel, false)
: container.current.removeEventListener('wheel', handleWheel, false);
};
setEvent(true);
return () => {
setEvent(false);
};
}, []);
return (
<div
ref={container}
className="bg-white h-screen w-full p-header pb-4 px-4 h-full flex justify-center align-middle items-center"
>
<div className="flex flex-col justify-center items-center h-p70 w-10/12 bg-red-500 overflow-hidden">
{team[persona]}
</div>
</div>
);
};
export default Equipo;
Вот еще один способ сделать это используя функцию газа вместо тайм-аутов. Таким образом, я считаю, что это чище, так как вам не нужно беспокоиться о реферах и тайм-аутах. Это также более нормальный способ убедиться, что функция выполняется только каждый период времени t.
Вместо того, чтобы самостоятельно связывать прослушиватель событий, проще просто позволить реакции позаботиться об этом.
Сам код регулирования от https://blog.bitsrc.io/understanding-throttling-and-debouncing-973131c1ba07. Хотя вы можете так же легко использовать функцию газа loda sh.
export const Equipo = () => {
const [persona, setPersona] = useState(0);
const handleWheel = useCallback(
throttle((e) => {
e.stopPropagation();
if (Math.sign(e.deltaY) === -1) {
console.log('swipe DOWN');
setPersona((prevPers) => {
Math.max(0, prevPers - 1);
});
} else {
console.log('swipe UP');
setPersona((prevPers) => Math.min(team.length, prevPers + 1));
}
}, 3000),
[team.length]
);
return (
<div
onWheel={handleWheel}
className="bg-white h-screen w-full p-header pb-4 px-4 h-full flex justify-center align-middle items-center"
>
<div className="flex flex-col justify-center items-center h-p70 w-10/12 bg-red-500 overflow-hidden">
{team[persona]}
</div>
</div>
);
};
export default Equipo;
function throttle(f, t) {
let lastCall;
return function (args) {
let previousCall = lastCall;
lastCall = Date.now();
if (
previousCall === undefined || // function is being called for the first time
lastCall - previousCall > t
) {
// throttle time has elapsed
f(args);
}
};
}
Объяснение того, почему персона всегда была 0:
In Javascript, когда функция создается, он создает то, что известно как замыкание, где он извлекает все переменные, которые существуют в его области видимости, и позволяет функции всегда иметь доступ к ним. MDN для замыканий
То, что происходило, состояло в том, что когда useEffect
работал при монтировании, он получал текущую версию функции setEvent
, и у него был бы доступ к текущей версии функции handleWheel
. setEvent
свяжет эту оригинальную версию handleWheel
с div и никогда не сможет обновить привязанную версию handleWheel
. Из-за замыканий исходная функция handleWheel
имеет замыкание вокруг персонажа, когда персона была равна 0. И поскольку при каждом повторном рендеринге всегда есть новый экземпляр переменной персонажа, закрытая переменная никогда не обновлялась.
По сути, именно так выглядел ваш код в useEffect. Надеюсь, это поможет вам понять, почему у вас возникли проблемы.
useEffect(() => {
const setEvent = (status) => {
const handleWheel = (e) => {
e.stopPropagation();
setEvent(false);
if (Math.sign(e.deltaY) === -1) {
console.log('swipe DOWN');
if (persona > 0) {
setPersona((prevPers) => prevPers - 1);
}
} else {
console.log('swipe UP');
if (persona <= team.length) {
setPersona((prevPers) => prevPers + 1);
}
}
setTimeout(() => {
console.log('available to scroll');
setEvent(true);
}, 3000);
};
status === true
? container.current.addEventListener('wheel', handleWheel, false)
: container.current.removeEventListener('wheel', handleWheel, false);
};
setEvent(true);
}, []);