useEffect 在一个非常简单的 NextJS 应用程序(v13.4+,应用程序路由器)中运行 3 次。为什么会这样?

useEffect running 3 times in a very simple NextJS app (v13.4+, app router). Why is this the case?

提问人:Andrew Chung 提问时间:11/17/2023 最后编辑:Henry WoodyAndrew Chung 更新时间:11/19/2023 访问量:44

问:

我在 v13.4+ 中有一个非常简单的 NextJS 应用程序,它运行 useEffect 3 次(即使它设置了一个空的依赖数组。

我希望由于空数组,它只会运行 1 次(相当于 componentDidMount)。

我不确定为什么useEffect运行了三次。我在useEffect中放置了一个getData调用,我希望当用户转到页面时不要运行三次。

// /app/page.js
import react, { useEffect, useState } from 'react'
    
export default Page() {
    
    const [myData, setMyData] = useState([]);

    // this is calling a router handler
    const getData = async () => {
        const response = await fetch('/api/data', {
            method: 'GET',
        });

        if (response.ok) {
            console.log('Response.Ok');
            const { data } = await response.json();
            setMyData((prev) => data);
        } else {
            console.log('Error');
        }
    };

    useEffect(() => {
      getData();
    }, [])
    
    return (<div>{myData.map((item, index)=>(<div>item.name</div>)}</div>)
}
reactjs next.js vercel next.js13

评论

0赞 Henry Woody 11/17/2023
你能展示渲染的父组件吗?Page
0赞 Youssouf Oumar 11/17/2023
你有没有退房 stackoverflow.com/questions/72238175/....
0赞 Octo Palm Tree 11/17/2023
亨利 - 没有父组件 ..它只是 NextJS 中的一个独立页面。

答:

0赞 freson 11/17/2023 #1

组件是纯组件,问题很可能出在父组件中。也许某些道具正在更改,从而导致子组件重新渲染。

请记住:如果父组件直接传递子组件,子组件将不会重新渲染,然后触发其生命周期钩子{children}

别忘了 React 严格模式:https://stackoverflow.com/a/60619061/15604836

0赞 Octo Palm Tree 11/18/2023 #2

如果您在本地(从终端/本地主机)运行您的应用程序,则在代码发生更改时,NextJS 会将更改推送到您正在运行的应用程序实例(无论您是否正在积极查看选项卡)。这可能是问题的根源。


在 NextJS v13.4.7 中,React Strict 模式默认处于关闭状态。通过对 useEffect 运行多少次进行一些实验,我可以确认严格模式默认处于关闭状态。app router

转到项目根目录下的文件,您将看到以下内容(您可以在其中打开或关闭它)。next.config.js

// STRICT MODE IS OFF BY DEFAULT
/** @type {import('next').NextConfig} */
const nextConfig = {
};

module.exports = nextConfig;


// STRICT MODE ON - THIS DOES INCREASE TIMES USE EFFECT IS RUN BY 1 
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
};

module.exports = nextConfig;


// STRICT MODE EXPLICITLY OFF - THIS MATCHES THE DEFAULT CASE 
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: off,
};

module.exports = nextConfig;

H/T 到引用 React Strict 模式的评论和答案。

0赞 Arman Kazi 11/19/2023 #3

你实际上错了,在 next.js 13.4+ 中,在开发模式下默认启用 react strict 模式。你必须让它变成假的,才能像生产一样工作。

https://nextjs.org/docs/app/api-reference/next-config-js/reactStrictMode