A Real Performance Bug I Found and Fixed — Step by Step
6 mins read

A Real Performance Bug I Found and Fixed — Step by Step


A few days ago, while working on a bug at work, I noticed something odd: after I fixed the bug, the default client name value in a dropdown component took almost 2 to 3 seconds to appear after the page loaded. That kind of lag is probably unacceptable to users, so I know I had to dig deeper.

Turns out, it was a performance issue.

We always hear advice like “don’t optimize prematurely” or “only solve performance problems when they exist.” Well, this was the first time I actually ran into one myself — and I think the debugging process is worth documenting.

In this post, I’ll walk through how I tracked down the cause of the slowdown. I can’t share the actual code or logs because of company policy, but I’ll reconstruct the process using pseudocode and reasoning steps. If you’re a frontend developer wondering how to approach a performance issue in a React app, I hope this gives you something concrete to take away.



If it’s not the API call, what is it?

When I first noticed the lag in how the client name appeared, my instinct was to check the Network tab. I opened DevTools and placed the network panel side-by-side with the UI so I could watch what was happening in real time. Sure enough, the API call to fetch client name came back quickly with a 200 OK. But even though the data returned fast, the client name still appeared in the dropdown field with a noticeable delay.

That made me pause — if it’s not the network latency, then what is? Could it be something in the frontend rendering cycle? Maybe Formik? Maybe context?

Here’s a bit of background. The client name is fetched from an API call and saved into the userInfo object, which lives in a global context. Formik pulls its initial values from this context. But initial values alone aren’t reactive — they don’t update just because the context does. So after the context gets the latest client name, I also call setFieldValue to make sure the form reflects the updated value.

At this point, I suspected the delay might be happening somewhere in that chain — from receiving the data to updating the form. So the question became: where exactly is the bottleneck?



Verifying data flow from API to form

My next step was to check how state updates propagated after the API call. The question was: after updating the context with the new client name, how exactly does that value reach the Formik form? I suspected a useEffect inside the page component (called Summary) might be responsible for syncing the values. So I added logs to verify the data flow step by step.



Step 1: Log inside Summary’s useEffect to confirm form syncing

useEffect(() => {
  console.log('[Summary] dealInfo.clientName effect triggered:', dealInfo?.clientName);

  if (dealInfo?.clientName?.trim()) {
    setFieldValue('summary.clientName', dealInfo.clientName);
  }
}, [dealInfo?.clientName]);
Enter fullscreen mode

Exit fullscreen mode

This log shows when the dealInfo.clientName value changes and triggers the code that updates the Formik field. It helps verify whether the effect runs immediately after the context updates — or if there’s any unexpected delay.



Step 2: Log right after receiving the API response

The clientName comes from an API call. Once the response is received, I update the global context via setDealInfo. To confirm that part was working correctly, I added a log right before updating the context:

setDealInfo(prev => {
  const updated = {
    ...prev,
    clientName: response.clientName, // from API response
  };
  console.log('[setDealInfo] triggered with:', updated);
  return updated;
});
Enter fullscreen mode

Exit fullscreen mode

This shows exactly when the client name arrives from the backend and enters the shared state.



Here’s what I saw:

On initial render, the useEffect ran quickly — but clientName was still empty, so setFieldValue was not called.

Then nothing happened for about 2–3 seconds.

After that delay, both the setDealInfo log and the useEffect log appeared almost at the same time.

The dropdown updated immediately after that.

This clearly shows that the 2–3 second delay was not due to slow state propagation or form logic. The delay happened before the context or form had any chance to react — meaning:

the bottleneck was simply the API call being slow to return.



Measure the API Call Duration Precisely

Now that I suspect the API call might be slow, the next step is to confirm this with accurate timing logs.

I added these logs inside the loadClientDetails function — the one that calls the backend API to fetch client name:

console.time('[loadClientDetails] API call');

const response = await axios.get('/api/clientDetails', { params: { externalId } });

console.timeEnd('[loadClientDetails] API call');

setDealInfo(prev => {
  const updated = {
    ...prev,
    clientName: response.data.clientName,
  };
  console.log('[setDealInfo] triggered with:', updated);
  return updated;
});
Enter fullscreen mode

Exit fullscreen mode

This lets me measure exactly how long the API request takes from start to finish.



What I saw:

I ran the test 4 times, and the results varied wildly:

  • About 4000 ms (4 seconds)
  • About 8000 ms (8 seconds)
  • About 15000 ms (15 seconds)
  • About 1000 ms (1 second)

This confirmed without doubt that the API is the bottleneck and sometimes responds very slowly.



Minimal Fix: Show Loading Clearly, Don’t Wait in Confusion

The simplest and most effective fix was to explicitly handle the loading state on the Summary page.

Since the page already had a loading spinner for the segment data (fetched via useQuery), I added a similar one for the client name:

if (segmentIsLoading) {
  return <LoadingSpinner label="Loading segment..." />;
}

if (!dealInfo.clientName) {
  return <LoadingSpinner label="Loading client name..." />;
}
Enter fullscreen mode

Exit fullscreen mode

This way, users immediately see that data is loading — instead of staring at an empty field, wondering if something’s broken.

✅ Problem solved. Happy debugging — and happy summer. ☀️



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *