Next.js 13中onClick箭头函数调用setState触发无限循环问题
Next.js 13中setState触发无限循环的解决办法
你的问题核心根本不是onClick里调用setState的写法错了——你贴的简化版组件代码完全没问题,点击按钮只会正常切换状态,不会触发无限循环。真正的问题出在原组件里获取多语言数据的方式。
问题根源
你在组件里用了const locales = use(getLocales()),每次组件渲染时,getLocales()这个异步函数都会被重新执行一遍。当你点击按钮调用setDropdownCollapsed修改状态时,组件会触发重渲染,这又会再次调用getLocales()发起Apollo查询,查询完成后数据更新又会触发重渲染,如此往复就形成了无限循环。
正确的解决方式
在Next.js 13的客户端组件里,应该用Apollo Client专门为Suspense设计的useSuspenseQuery钩子来获取数据,而不是手动调用client.query再配合React的use函数。
修改后的完整组件代码如下:
'use client' import { useState } from "react"; import { useSuspenseQuery } from "@apollo/client"; import { localesQuery } from '/graphql/queries'; // Import Components import { LanguageIcon } from '@heroicons/react/24/solid' import Image from 'next/image'; export default function LanguageSwitcher({className}) { // 用useSuspenseQuery替代手动调用client.query和use函数 const { data } = useSuspenseQuery(localesQuery); const locales = data.i18NLocales.data; const [dropdownCollapsed, setDropdownCollapsed] = useState(false); return ( <button className={className} onClick={() => setDropdownCollapsed(!dropdownCollapsed)}> <LanguageIcon className="h-5 w-5 text-dark dark:text-white"/> {/* 根据dropdownCollapsed状态控制下拉框显示/隐藏 */} {dropdownCollapsed && ( <div className="dropdown-list absolute right-0 -bottom-4 transform translate-y-full transition-colors duration-150 border border-gray-200 dark:border-gray-800 bg-white dark:bg-black md:bg-opacity-70 rounded-2xl overflow-hidden "> <ul className="w-40 flex flex-col"> {locales.map((locale) => ( <li key={locale.id}> {/* 用locale的唯一id作为key,替代index更可靠 */} <a className="flex items-center px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-900 w-full"> <Image height="20" width="24" className="rounded mr-1.5" src={`images/${locale.attributes.code}.svg`} alt={`${locale.attributes.name} flag`} /> <span>{locale.attributes.name}</span> </a> </li> ))} </ul> </div> )} </button> ) }
额外优化点
- 原代码里的下拉框没有根据
dropdownCollapsed状态控制显示,现在加上了{dropdownCollapsed && (...)},点击按钮就能正常切换下拉框的显示/隐藏。 - 列表项的key改用
locale.id这种唯一标识,避免用index可能导致的列表更新异常。
内容的提问来源于stack exchange,提问作者Douwe Pausma
相关产品推荐
相关产品推荐

