轮播图组建需要自动轮播,我想到了使用 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]);
嘿嘿,有问题不能自己死磕,还是得问问!