轮播图组建需要自动轮播,我想到了使用 setTimeout 来解决 setInterval 可能越来越快的问题。心里想着:这我还不轻松拿下?一番奋战后于是就有了以下代码
const Swiper: React.FC<SwiperProps> = (props) => {
const {
autoplay,
duration,
} = props;
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [timer, setTimer] = useState<number>();
const childrenLength = React.Children.count(children);
function next() {
if (currentIndex > childrenLength - 2) {
setCurrentIndex(0);
}
else {
setCurrentIndex(currentIndex + 1);
}
}
function prev() {
if (currentIndex <= 0) {
setCurrentIndex(childrenLength - 1);
}
else {
setCurrentIndex(currentIndex - 1);
}
}
// TODO autoplay
function autoPlay() {
if (autoplay) {
// eslint-disable-next-line unicorn/no-new-array
new Array(React.Children.count(children))
.fill(0)
.forEach(() => {
return new Promise((resolve) => {
const timerId = setTimeout(() => {
next();
}, duration);
setTimer(timerId);
resolve(true);
});
});
}
}
useEffect(() => {
autoPlay(); // error
return () => {
if (autoplay)
clearTimeout(timer);
};
}, [timer, currentIndex, autoplay]);
return (
// ...组件内容
<div />
);
};
Swiper.defaultProps = {
// ...
};
export default Swiper;
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render
这时会报错且页面不能加载(报错详情见上文)。在我询问了群里的大佬后,得知有一个 useCallback 貌似可以解决我的问题。
于是按着大佬的思路,我做了如下改造:
使用 useCallback 将 next 和 autoPlay 进行了一次包装。
为什么要使用 useCallback 将 next 函数也进行改造呢?
不使用 useCallback 将 next 进行包裹会有如下报错: Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render
const next = useCallback(() => {
if (currentIndex > childrenLength - 2) {
setCurrentIndex(0);
}
else {
setCurrentIndex(currentIndex + 1);
}
}, [currentIndex, childrenLength]);
useEffect(() => {
// autoPlay(); // error
const autoPlay = useCallback(() => {
const timer = setTimeout(() => {
next();
autoPlay();
}, duration);
return () => {
if (autoplay)
clearTimeout(timer);
};
}, [timer, currentIndex, autoplay]);
}, [duration, next, autoplay]);
useEffect(() => {
if (autoplay) {
autoPlay();
}
}, [autoplay, autoPlay]);
嘿嘿,有问题不能自己死磕,还是得问问!
评论区
评论加载中...