This function convertToUpperCase(item.name)
runs 3-150 times. You can see it in context below.
In my test db, I have only 1 row of data in my db that I am returning so I am expecting it to run only 1 time.
// /app/Tacos/page.js
'use client';
import React, { useEffect, useState } from 'react';
//this runs 3-150 times (with only 1 row of data in the db).
const convertToUpperCase = (param) => {
console.log('convertToUpperCase');
return param.toUpperCase();
};
export default function Page() {
const [myData, setMyData] = useState([]);
var randomNum = 1;
//this runs 1 time
// this is calling a router handler
const getData = async () => {
const response = await fetch('/api/tacos', {
method: 'GET',
});
if (response.ok) {
console.log('Response.Ok');
const { data } = await response.json();
console.log(data);
setMyData((prev) => data);
} else {
console.log('Error');
}
};
// this runs 1 time
useEffect(() => {
console.log('useEffect');
getData();
}, []);
// Experimented with the location of this function which did not make a difference
// //this runs 3-150 times (with only 1 row of data in the db).
// const convertToUpperCase = (param) => {
// console.log('convertToUpperCase');
// return param.toUpperCase();
// };
return (
<div className='text-3xl text-white'>
{myData.map((item, index) => (
<div key={index}>{convertToUpperCase(item.name)}</div>
))}
</div>
);
}
Please make sure that React Strict Mode is explicitly turned off:
// ./next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
};
module.exports = nextConfig;
For the sake of the experiment, here is a very simple route handler that can be used:
import { NextRequest, NextResponse } from 'next/server';
export async function GET(req) {
const data = [
{ name: 'taco' },
];
return Response.json({ data });
}
This is running from Terminal locally.
I am seeing the counts in Visual Studio Code with a console logger.
I’m thinking through what the possibilities of this could be.
Obviously, the above is an miniature isolation of the problem but I’ll test to see if this issue appears even in this use case and then start adding more and more of the rest of the code on this page (or subtracting from the larger code base) until something pops but if the code ^ alone points to a recognizable pattern, I would appreciate it.
2
Answers
TLDR;
[Fast Refresh) rebuilding
, and in this rebuilding process will run convertToUpperCase 3 times (sometimes 4) and the order of convertToUpperCase with respect will change from rebuild to rebuild[Fast Refresh] rebuilding
will beconvertToUpperCase
and the number of times that first one runs will be based on the previous build (e.g. it will use some cached value)End TLDR;
I ran various experiments to see if I could replicate the issue. For the experiments, I am keep track of console logger in VSCode and cross referencing this in Chrome browser dev tools.
The four
console.log's
I am keeping track of:The scenarios:
VSCode (in order it appears in code):
Chrome (in the order it appears in Console):
Looking at the Chrome dev tools, this is both the order and number I was expecting.
var randomNum = 1;
, this would reset the console counts in VSCode but also did something unexpected (outputted[Fast Refresh] rebuilding
which helped pinpoint the issue.So, while the app is up in Chrome, running localhost in terminal there are the counts:
VSCode (in order it appears in code):
Chrome (in the order it appears in Console):
This is unexpected, regardless of rebuild or refresh I was still expecting the number of times
convertToUpperCase
to follow code flow. However, this is good to know at least one source of where the issue was stemming from and I explained it away as saying, "Perhaps the rebuild runs the various functions and outputs the console a few extra times?" ... but this doesn't fully make sense as onlyconvertToUpperCase
is run more than the other ones.Then for completeness, ran this same experiment (changing the randomNum and saving to trigger the rebuild) a few more times. This is when it became even more confusing. The output sometimes changes to the following:
VSCode (in order it appears in code): //this is the same
Chrome (in the order it appears in Console): // Notice that the order changes
When running this a few times, this second ^ output order shows up a bit more. And sometimes, there is even another output that appears less frequently where convertToUpperCase runs 4 times:
So far, it seems there is something "fundamental" to the rebuilding process that makes the functions run in such a way that doesn't directly to what code flow would indicate.
It has covertToUpperCase running more often. This is not a useEffect or state-related function but something that is tied closely to the outputting of the HTML so perhaps this is related to React's screen painting process and perhaps there is something about a previous build or a cached value that it is using? (And is this part of the normal comparison/creation of Virtual DOM on updates at play in the rebuilding process.)
Is there something about having more data that makes this behavior unusual?
Of course this is not just to observe
"more rows of data leads x number of times function runs = a bigger number"
but instead investigating wether something about having more data can lead to unexpected changes in behavior.So I increased the returned array from 1 item to 30 items.
So the route handler became this:
I ran it a few times as well, and generally the results look like the following, and unfortunately didn't really learn anything new here. It was simply 30 times what I saw before:
VSCode (in order it appears in code):
Chrome (in the order it appears in Console):
x30
results, I opened this in a new tab. This is the second time things got interesting.Based on the previous results I was expecting something like this:
VSCode (in order it appears in code):
But instead got something like this:
VSCode (in order it appears in code):
Okay so here how it gets interesting.
Firstly, I was able to replicate "a big number without a simple explanation".
Second, I realized that having multiple tabs open will sum the values of what's happening on these tabs. I was only actively looking at one tab at the time. My understanding was that React was driven from the client side primarily and that users navigating to the pages or at least having active tabs open would trigger various events like useEffect(()=>{...}, []), etc. but it seems this is not the case.
Now this might only be applicable while running Terminal/localhost...perhaps this is NextJS running a listener that listens for changes in code and actively pushes these changes to each instance regardless of whether the tab is open. I'm not sure that this would be the same behavior if this is running from a remote server (ie. production or remote dev server.)
Thirdly, breaking down the number 68 (which is the number of times convertToUpperCase ran) is the second interesting thing I saw. Normally you would expect 12 which would (2 + 2 + 2) * 2 for each tab. Looking in Chrome I saw the following.
Chrome (in the order it appears in Console):
And then in the next rebuild it shows up like this: Chrome (in the order it appears in Console):
So to summarize where that 68 number came from VSCode (in order it appears in code):
So the bottom line is this:
[Fast Refresh) rebuilding
, and in this rebuilding process will run convertToUpperCase 3 times (sometimes 4) and the order of convertToUpperCase with respect will change from rebuild to rebuild[Fast Refresh] rebuilding
will beconvertToUpperCase
and the number of times that first one runs will be based on the previous build (e.g. it will use some cached value)You are using the convertToUpperCase function inside the map function, and the map is based on myData array, so convertToUpperCase will run for each element of myData.
The length of myData will determine how many times it will run. Otherwise what you do is, inside the getData function you can map through response data and make it uppercase.