NextJS 13.4+ App Router中useEffect执行3次的原因咨询
NextJS 13.4+ App Router中useEffect空依赖仍执行3次的原因及解决办法
原因分析
- React 18严格模式的双重执行:开发环境下,React 18的Strict Mode会强制重复执行
useEffect、组件函数等两次,目的是检测未正确清理的副作用问题,这是开发环境专属行为,生产环境会自动恢复单次执行。 - App Router的渲染流程:即使页面标记了
'use client',Next.js仍会先在服务器端完成初始渲染生成静态HTML,随后在客户端进行hydration(将静态HTML转为可交互组件),这次hydration会触发一次useEffect,加上Strict Mode的两次,就会出现总共3次执行。 - 代码依赖缺失的潜在影响:
getData函数定义在组件内部,每次组件渲染都会重新创建该函数,虽然你没将其加入useEffect依赖数组,但Strict Mode的检测机制可能间接导致额外执行(同时会引发ESLint警告)。
解决方法
1. 临时禁用Strict Mode(不推荐长期使用)
如果只是临时验证,可以在next.config.js中关闭Strict Mode,但不建议长期这么做,因为它能帮你提前发现很多潜在问题:
/** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: false, } module.exports = nextConfig
2. 用useCallback缓存函数并补充依赖
使用useCallback包裹getData,确保它不会随组件渲染重复创建,再将其加入useEffect依赖数组,既符合React规则,也能避免不必要的执行:
'use client'; import React, { useEffect, useState, useCallback } from 'react' export default function Page() { const [myData, setMyData] = useState([]); const getData = useCallback(async () => { const response = await fetch('/api/data', { method: 'GET', }); if (response.ok) { console.log('Response.Ok'); const { data } = await response.json(); setMyData(data); } else { console.log('Error'); } }, []); useEffect(() => { getData(); }, [getData]) return ( <div> {myData.map((item, index) => ( <div key={index}>{item.name.toUpperCase()}</div> ))} </div> ) }
3. 改用服务器组件预获取数据(推荐)
遵循Next.js App Router的最佳实践,直接在服务器组件中获取数据,数据会在服务器端预获取,无需客户端useEffect,从根源避免多次执行问题:
// /app/page.js(无需'use client'标记) export default async function Page() { const response = await fetch('http://localhost:3000/api/data', { method: 'GET', cache: 'no-store' // 根据需求设置缓存策略,如'static'、'force-cache'等 }); if (!response.ok) { throw new Error('Failed to fetch data'); } const { data } = await response.json(); return ( <div> {data.map((item, index) => ( <div key={index}>{item.name.toUpperCase()}</div> ))} </div> ) }
内容的提问来源于stack exchange,提问作者Octo Palm Tree
相关产品推荐
相关产品推荐

