Next.js 14中React-Intersection-Observer无限循环问题修复
问题:Next.js 14使用React-Intersection-Observer触发无限更新循环错误
我的Next.js 14应用在使用React-Intersection-Observer库时出现以下错误:
超出最大更新深度。当组件在componentWillUpdate或componentDidUpdate中反复调用setState时可能会发生这种情况。React限制嵌套更新的次数以防止无限循环。
我的代码如下:
"use client" import { useInView } from "react-intersection-observer"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; interface Props{ dark: boolean; } export const LoadMore = async ({dark}: Props) => { const { ref, inView } = useInView({ threshold: 0 }) const router = useRouter(); useEffect(() => { if(inView) router.push(`?page=${2}`, { scroll: false}); }, [inView]) return ( <> <div // 给这个div分配ref时就会出问题 ref={ref} className={`${!dark ? "lds-ellipsis" : "lds-ellipsis dark"} `}><div></div><div></div><div></div><div></div></div> </> ) }
我尝试用useCallback钩子但无效,请问如何修复该问题避免应用崩溃?
解决方案
问题根源
- 客户端组件不能是异步函数:你给
LoadMore组件加了async关键字,但Next.js的"use client"组件不能声明为异步(除非配合Suspense使用,但这里场景不需要),这会导致组件渲染逻辑异常,触发不必要的更新。 - 无限循环触发路由跳转:当元素进入视口时
inView变为true,触发router.push修改URL参数,页面重新渲染后会重新创建useInView实例,元素再次被判定为进入视口,又触发跳转,形成无限循环。
修复步骤
- 移除组件的
async关键字 - 添加状态标记是否已经执行过跳转,避免重复触发
- 可选:给
useInView添加triggerOnce: true配置,让 intersection 事件只触发一次
修复后的代码示例
"use client" import { useInView } from "react-intersection-observer"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; interface Props{ dark: boolean; } export const LoadMore = ({dark}: Props) => { // 添加triggerOnce: true,让只触发一次视口检测 const { ref, inView } = useInView({ threshold: 0, triggerOnce: true }) const router = useRouter(); // 状态标记是否已经触发过加载 const [hasLoaded, setHasLoaded] = useState(false); useEffect(() => { // 只有当元素在视口且未加载过时才执行跳转 if(inView && !hasLoaded) { setHasLoaded(true); router.push(`?page=${2}`, { scroll: false}); } }, [inView, hasLoaded, router]) return ( <> <div ref={ref} className={`${!dark ? "lds-ellipsis" : "lds-ellipsis dark"} `}> <div></div><div></div><div></div><div></div> </div> </> ) }
内容的提问来源于stack exchange,提问作者Danish Siddiqui
相关产品推荐
相关产品推荐

