近日在写 React 轮播图组件时遇到自动轮播的问题,在多方请教后,使用 useCallback 解决
轮播图组建需要自动轮播,我想到了使用 setTimeout 来解决 setInterval 可能越来越快的问题。心里想着:这我还不轻松拿下 ?一番奋战后于是就有了以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 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 ); } } function autoPlay ( ) { if (autoplay) { Array (React .Children .count (children)) .fill (0 ) .forEach (() => { return new Promise ((resolve ) => { const timerId = setTimeout (() => { next (); }, duration); setTimer (timerId); resolve (true ); }); }); } } useEffect (() => { autoPlay (); return () => { if (autoplay) clearTimeout (timer); }; }, [timer, currentIndex, autoplay]); return ( ...组建内容 ); }; 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const next = useCallback (() => { if (currentIndex > childrenLength - 2 ) { setCurrentIndex (0 ); } else { setCurrentIndex (currentIndex + 1 ); } } }, [currentIndex, childrenLength]); useEffect (() => { 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]);
嘿嘿,有问题不能自己死磕,还是得问问 !