Я наблюдаю странное поведение, при котором функция useCallback
не может получить доступ к внешней области видимости.
Это описано здесь: Как React Hooks использует CallCallback "зависает"замыкание?
Хотя его можно легко пересчитать, добавляя все элементы в массив, оно кажется нелогичным.Поэтому мне интересно, как лучше с этим справиться.
Вот код
import React, { useCallback, useState, useEffect, useRef } from 'react';
import classNames from 'classnames';
import useEventListener from '../../hooks/use-event-listener';
import tinybounce from 'tinybounce';
import Scroll from '../../utils/scroll';
export default function DefaultMainPlayer({ children, className }) {
const [scrollThreshold, setScrollThreshold] = useState(0);
const [inView, setInView] = useState(true);
const [didUserClose, setDidUserClose] = useState(false);
const el = useRef();
const scrollHandler = useCallback(() => {
// scrollThreshold and inView get "frozen" unless they're on the array below
const isVisible = Scroll.getPosition() <= scrollThreshold;
if (inView !== isVisible) {
if (inView) {
setInView(isVisible);
setDidUserClose(false);
}
}
}, [scrollThreshold, inView]);
const cx = classNames('main-player', className, {
'is-fixed': !inView && !didUserClose
});
const resizeHandler = useCallback(
tinybounce(() => setScrollThreshold(Scroll.getElementCoordinates(el.current).bottom), 300),
[]
);
// If scroll threshold updates, lets call the scroll handler
useEffect(scrollHandler, [scrollThreshold]);
// Call the resize handler once
useEffect(resizeHandler, []);
// I'd like the scroll handler to never change since it really doesn't need to
useEventListener('scroll', scrollHandler);
useEventListener('resize', resizeHandler);
return (
<div className={cx} ref={el}>{children}</div>
);
}
Вот код для `use-event-listener``
import { useRef, useEffect } from 'react';
export default function useEventListener(eventName, handler, element = window) {
const savedHandler = useRef();
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
const isSupported = element && element.addEventListener;
if (!isSupported) return;
const eventListener = event => savedHandler.current(event);
// Add event listener
element.addEventListener(eventName, eventListener);
// Remove event listener on cleanup
return () => {
element.removeEventListener(eventName, eventListener);
};
},
[eventName, element]
);
};
Я стараюсь не менять scrollHandler
все время, потому что функции не равны.Я пытался useMemo
(возвращая функцию в качестве значения), но результат тот же.Не обновляйте scrollThreshold
.
Хотя эти две переменные могут показаться «маленькими», им может понадобиться больше, и это просто кажется неправильным.
Есть ли способ исправить это илиподходить к этому по-другому?