You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13.4+ App Router函数执行次数异常问题求助

问题原因与解决方案

核心原因

你遇到的问题本质是React组件渲染机制导致的重复执行:

  • React每次渲染组件时,JSX中的所有表达式都会重新执行。只要组件因为任何原因触发重渲染(比如状态更新、父组件重渲染、开发环境的热更新/额外检查),myData.map里的convertToUpperCase就会被调用一次。
  • 开发模式下Next.js App Router会有额外的渲染行为(比如热模块替换HMR、开发环境的内部校验),即使关闭了Strict Mode,也可能导致组件多次重渲染,进而让这个函数被调用几十甚至上百次。

解决方案

有两种高效的方式解决这个问题,从根源避免重复执行转换逻辑:

1. 数据获取时直接转换(推荐)

把转换逻辑放在接口请求的回调里,只在拿到数据时执行一次,后续渲染直接使用转换后的值:

// /app/Tacos/page.js
'use client';
import React, { useEffect, useState } from 'react';

export default function Page() {
    const [myData, setMyData] = useState([]);

    const getData = async () => {
        const response = await fetch('/api/tacos', { method: 'GET' });
        if (response.ok) {
            const { data } = await response.json();
            // 在这里完成转换,只执行一次
            const transformedData = data.map(item => ({
                ...item,
                name: item.name.toUpperCase()
            }));
            setMyData(transformedData);
        } else {
            console.log('Error');
        }
    };

    useEffect(() => {
        getData();
    }, []);

    return (
        <div className='text-3xl text-white'>
            {myData.map((item, index) => (
                <div key={index}>{item.name}</div>
            ))}
        </div>
    );
}

2. 使用useMemo缓存转换结果

如果必须在组件内处理转换逻辑,用useMemo缓存转换后的数据,仅当myData变化时才重新计算:

// /app/Tacos/page.js
'use client';
import React, { useEffect, useState, useMemo } from 'react';

const convertToUpperCase = (param) => {
    console.log('convertToUpperCase');
    return param.toUpperCase();
};

export default function Page() {
    const [myData, setMyData] = useState([]);

    const getData = async () => {
        const response = await fetch('/api/tacos', { method: 'GET' });
        if (response.ok) {
            const { data } = await response.json();
            setMyData(data);
        } else {
            console.log('Error');
        }
    };

    useEffect(() => {
        getData();
    }, []);

    // 缓存转换结果,仅myData变化时重新执行
    const transformedData = useMemo(() => {
        return myData.map(item => ({
            ...item,
            name: convertToUpperCase(item.name)
        }));
    }, [myData]);

    return (
        <div className='text-3xl text-white'>
            {transformedData.map((item, index) => (
                <div key={index}>{item.name}</div>
            ))}
        </div>
    );
}

补充说明

  • 生产环境下这种重复执行的情况会大幅减少,因为Next.js会开启更严格的优化策略,组件重渲染次数会降低。
  • 尽量避免在JSX中直接调用复杂函数,优先在数据处理阶段完成转换,或者用缓存手段减少不必要的计算。

内容的提问来源于stack exchange,提问作者Octo Palm Tree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:34:50