Next.js 13中点击事件改状态触发无限循环,箭头函数无效
问题分析与解决方案
这不是Next.js 13特有的问题,核心是客户端组件误用async声明+useCallback依赖/闭包陷阱导致的异常渲染。
问题原因
- 客户端组件不能是async函数:Next.js 13中,标记
'use client'的组件必须是同步函数,async组件仅用于服务器组件。你的代码里把客户端组件声明为async function Page(),这种混合写法会触发组件渲染逻辑异常,引发重复渲染。 - useCallback的闭包问题:你的
useCallback依赖数组为空,回调函数捕获的是组件初始化时的vidModal状态。每次调用setVidModal时,都是基于初始状态更新,组件重新渲染后cb仍保留旧闭包,状态更新逻辑异常,进一步加剧渲染循环。
修复步骤
- 移除async声明:将客户端组件改为普通同步函数
'use client' import { useState, useCallback } from 'react' export default function Page() { // 去掉async关键字 // initialize state const [vidModal, setVidModal] = useState({ open: false, videoId: '', opts: {} }) // 后续代码... }
- 修正状态更新逻辑:二选一即可
- 方案一:给useCallback添加正确依赖
const cb = useCallback(() => { setVidModal({...vidModal, open: !vidModal.open}); }, [vidModal]) // 加入vidModal作为依赖项 - 方案二:使用函数式更新避免闭包陷阱(推荐)
const cb = useCallback(() => { setVidModal(prevState => ({...prevState, open: !prevState.open})); }, []) // 依赖数组可保持为空
- 方案一:给useCallback添加正确依赖
效果验证
修改后,点击img元素时vidModal状态会正确切换,控制台的console.log(vidModal)只会在状态真正变化时打印,不会出现无限循环打印的情况。
内容的提问来源于stack exchange,提问作者DatMomoAgain
相关产品推荐
相关产品推荐

