[{"data":1,"prerenderedAt":107},["ShallowReactive",2],{"content:\u002Fposts\u002F2023\u002Freact-usecallback-use":3,"surround:\u002Fposts\u002F2023\u002Freact-usecallback-use":95},{"id":4,"title":5,"body":6,"canonical":68,"categories":69,"date":71,"description":72,"draft":73,"extension":74,"image":68,"meta":75,"navigation":76,"path":77,"permalink":68,"readingTime":78,"recommend":68,"references":83,"seo":87,"sitemap":88,"stem":91,"tags":92,"type":68,"updated":71,"__hash__":94},"content\u002Fposts\u002F2023\u002Freact-useCallback-use.md","React useCallback使用",{"type":7,"value":8,"toc":65},"minimark",[9,13,24,30,33,39,42,45,56,62],[10,11,12],"p",{},"轮播图组建需要自动轮播，我想到了使用 setTimeout 来解决 setInterval 可能越来越快的问题。心里想着：这我还不轻松拿下？一番奋战后于是就有了以下代码",[14,15,21],"pre",{"className":16,"code":18,"language":19,"meta":20},[17],"language-tsx","const Swiper: React.FC\u003CSwiperProps> = (props) => {\n    const {\n        autoplay,\n        duration,\n    } = props;\n\n    const [currentIndex, setCurrentIndex] = useState\u003Cnumber>(0);\n    const [timer, setTimer] = useState\u003Cnumber>();\n    const childrenLength = React.Children.count(children);\n\n    function next() {\n        if (currentIndex > childrenLength - 2) {\n            setCurrentIndex(0);\n        }\n        else {\n            setCurrentIndex(currentIndex + 1);\n        }\n    }\n\n    function prev() {\n        if (currentIndex \u003C= 0) {\n            setCurrentIndex(childrenLength - 1);\n        }\n        else {\n            setCurrentIndex(currentIndex - 1);\n        }\n    }\n\n    \u002F\u002F TODO autoplay\n    function autoPlay() {\n        if (autoplay) {\n            \u002F\u002F eslint-disable-next-line unicorn\u002Fno-new-array\n            new Array(React.Children.count(children))\n                .fill(0)\n                .forEach(() => {\n                    return new Promise((resolve) => {\n                        const timerId = setTimeout(() => {\n                            next();\n                        }, duration);\n                        setTimer(timerId);\n                        resolve(true);\n                    });\n                });\n        }\n    }\n\n    useEffect(() => {\n        autoPlay(); \u002F\u002F error\n        return () => {\n            if (autoplay)\n                clearTimeout(timer);\n        };\n    }, [timer, currentIndex, autoplay]);\n\n    return (\n    \u002F\u002F ...组件内容\n        \u003Cdiv \u002F>\n    );\n};\n\nSwiper.defaultProps = {\n    \u002F\u002F ...\n};\n\nexport default Swiper;\n","tsx","",[22,23,18],"code",{"__ignoreMap":20},[25,26,27],"alert",{},[10,28,29],{},"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",[10,31,32],{},"这时会报错且页面不能加载（报错详情见上文）。在我询问了群里的大佬后，得知有一个 useCallback 貌似可以解决我的问题。",[10,34,35],{},[36,37],"img",{"alt":20,"src":38},"https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002F679adde397afa-78.webp",[10,40,41],{},"于是按着大佬的思路，我做了如下改造:",[10,43,44],{},"使用 useCallback 将 next 和 autoPlay 进行了一次包装。",[25,46,47,53],{},[48,49,50],"template",{"v-slot:title":20},[10,51,52],{},"为什么要使用 useCallback 将 next 函数也进行改造呢？",[10,54,55],{},"不使用 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",[14,57,60],{"className":58,"code":59,"language":19,"meta":20},[17],"const next = useCallback(() => {\n    if (currentIndex > childrenLength - 2) {\n        setCurrentIndex(0);\n    }\n    else {\n        setCurrentIndex(currentIndex + 1);\n    }\n}, [currentIndex, childrenLength]);\n\nuseEffect(() => {\n    \u002F\u002F autoPlay();  \u002F\u002F error\n    const autoPlay = useCallback(() => {\n        const timer = setTimeout(() => {\n            next();\n            autoPlay();\n        }, duration);\n\n        return () => {\n            if (autoplay)\n                clearTimeout(timer);\n        };\n    }, [timer, currentIndex, autoplay]);\n}, [duration, next, autoplay]);\n\nuseEffect(() => {\n    if (autoplay) {\n        autoPlay();\n    }\n}, [autoplay, autoPlay]);\n",[22,61,59],{"__ignoreMap":20},[10,63,64],{},"嘿嘿，有问题不能自己死磕，还是得问问！",{"title":20,"searchDepth":66,"depth":66,"links":67},4,[],null,[70],"代码","2023-02-09 18:11:51","近日在写 React 轮播图组件时遇到自动轮播的问题，在多方请教后，使用 useCallback 解决",false,"md",{},true,"\u002Fposts\u002F2023\u002Freact-usecallback-use",{"text":79,"minutes":80,"time":81,"words":82},"3 min read",2.305,138300,461,[84],{"title":85,"link":86},"react useCallback","https:\u002F\u002Fbeta.reactjs.org\u002Freference\u002Freact\u002FuseCallback#usecallback",{"title":5,"description":72},{"loc":77,"images":89},[90],{"loc":38},"posts\u002F2023\u002Freact-useCallback-use",[93],"React","CBOIDtZ3BjzMU85Hp4JYxxykBCYOd86LCDooKfYMQkM",[96,102],{"title":97,"path":98,"stem":99,"date":100,"type":101,"children":-1},"驾照考试记录","\u002Fposts\u002F2023\u002Fdriving-test-record","posts\u002F2023\u002FDriving-test-record","2023-02-08 22:46:24","story",{"title":103,"path":104,"stem":105,"date":106,"type":101,"children":-1},"大同博物馆游览留念","\u002Fposts\u002F2023\u002Fdatong-museum-tour-souvenir","posts\u002F2023\u002FDatong-Museum-tour-souvenir","2023-02-11 12:31:14",1789642594686]