Я пытаюсь сделать карусель, реагируя на некоторые анимации. У меня есть некоторое состояние, настроенное для изменения текущего рендеринга дочернего элемента + должны ли появляться переходы затухания.
Я сталкиваюсь с некоторыми проблемами
- иногда пользователь меняет страницу и
setTimeout
внутри next()
и previous()
будут срабатывать, и я получаю консольную ошибку об изменении состояния после размонтирования компонента. - Пользователь может просто спамить следующую / предыдущую кнопку и всю карусель даст кому-то приступ
Я уже реорганизовал start()
и stop()
, чтобы использовать intervalRef
, и у меня есть ощущение, что преобразование тайм-аутов в timeoutRef
решит обе эти проблемы проблемы, но я не уверен, как
type Props = {
interval?: number;
timeout?: number;
children: React.ReactNodeArray;
}
const Carousel: React.FC = ({ interval = 4000, timeout = 500, children }) => {
const [fade, setFade] = useState(true); // Start fade animation
const [childIndex, setChildIndex] = useState(0); // Which child to render
const intervalRef = useRef<NodeJS.Timer | null>(null);
const next = useCallback(() => {
setFade(false); // do the fade out animation
setTimeout(() => {
setChildIndex((pIndex) => (pIndex + 1) % children.length); // update which to display
setFade(true); // display fade in animation
}, timeout);
}, [timeout, children]);
const previous = useCallback(() => {
setFade(false); // do the fade out animation
setTimeout(() => {
setChildIndex((pIndex) => ((pIndex - 1) + children.length) % children.length); // update which to display
setFade(true); // display fade in animation
}, timeout);
}, [timeout, children]);
const start = useCallback(() => {
if (intervalRef.current === null) {
intervalRef.current = setInterval(next, interval);
}
}, [next, interval]);
const stop = useCallback(() => {
if (intervalRef.current !== null) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}, []);
useEffect(() => {
start();
return () => stop();
}, [start, stop]);
return (
<>
<Fade in={fade} timeout={timeout} onMouseEnter={stop} onMouseLeave={start}> // don't switch item on hover
<div>
{children[childIndex]}
</div>
</Fade>
<Button onClick={previous}>Previous</Button>
<Button onClick={next}>Next</Button>
</>
)
}