如何解决在让 useEffect、useCallback 和 setTimeout 协同工作时遇到一些麻烦
尝试根据宽度为滑块实现一些自定义滚动行为。它使用 useState 来跟踪滑块内的当前页面和总页面。这是我最终尝试编译的代码,但它有一些意外的行为。
const [isTimeoutLocked,setIsTimeoutLocked] = useState(false)
const handleScroll = useCallback(() => {
const gridContainer = document.querySelector(".grid");
const totalPages = Math.ceil(
gridContainer.scrollWidth / gridContainer.clientWidth + -0.1
);
setTotalPages(totalPages);
const scrollPos = gridContainer.clientWidth + gridContainer.scrollLeft + 2;
if (gridContainer.scrollWidth > scrollPos) {
gridContainer.scrollBy({
left: gridContainer.clientWidth + 20.5,behavior: "auto",block: "center",inline: "center",});
setCurrentPage(currentPage + 1);
setIsTimeoutLocked(false)
} else {
gridContainer.scrollTo(0,0);
setCurrentPage(1);
setIsTimeoutLocked(false)
}
},[currentPage]);
useEffect(() => {
if(!isTimeoutLocked){
setTimeout(() => {
setIsTimeoutLocked(true)
document.querySelector(".grid") && handleScroll();
},5000);
}
},[currentPage,displayDate,isTimeoutLocked,handleScroll]);
这里的问题是,当 currentPage 显示在 ui 中时,如果 else 在 handleScroll 函数内运行,它会重置回 1,这完全没问题,但它会返回到先前的值而不是返回到 2当它进入下一页时。此外,由于我已将 isTimeoutLocked 添加为 useEffect 的依赖项,因为它要求 setTimeout 将更频繁地运行,但我只想将其作为依赖项来获取正确的值,而不是每次更改时 useEffect 都会运行。 isTimeoutLocked 的目的是当您通过更改当前日期来更改容器内的内容时,它没有注册一堆超时。
解决方法
您应该为 useEffect 添加一个清理函数。由于您在 useEffect 中改变了 isTimeoutLocked
,因此它可以强制运行多个 setTimeouts,这可能是奇怪行为的结果。
在 useEffect 中使用 setTimeout 时,始终建议将其与清理一起使用。 Cleanup 将在下一次 useEffect 被触发之前运行,这让您有机会摆脱下一次 setTimeout 触发。它的代码是这样的:
useEffect(() => {
if(!isTimeoutLocked){
const tid = setTimeout(() => {
setIsTimeoutLocked(true)
document.querySelector(".grid") && handleScroll();
},5000);
// this is the cleanup function that is run before next useEffect
return () => clearTimeout(tid);
}
您可以在此处找到更多信息:https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup .
另一件需要注意的事情是 setState 和批处理的异步性质。由于您在 setTimeout 中使用 setState,React 将 NOT BATCH 它们,因此 handleScroll 中的 EVERY setState 将导致重新渲染(如果它不在 setTimeout/async 函数中) React 会对它们进行批处理)。由于您有很多相互关联的状态,因此您应该研究 useReducer。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。