<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Naufal Yukafi Ridlo</title>
    <description>The latest articles on Forem by Naufal Yukafi Ridlo (@naufalyukafi).</description>
    <link>https://forem.com/naufalyukafi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F508072%2Fc7180e7d-8575-4090-86e5-dbd002b7f231.jpeg</url>
      <title>Forem: Naufal Yukafi Ridlo</title>
      <link>https://forem.com/naufalyukafi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/naufalyukafi"/>
    <language>en</language>
    <item>
      <title>How I Reduced My Dashboard Bundle Size from 1.72 MB to 299 KB for Faster Loading</title>
      <dc:creator>Naufal Yukafi Ridlo</dc:creator>
      <pubDate>Sat, 01 Nov 2025 06:20:39 +0000</pubDate>
      <link>https://forem.com/naufalyukafi/how-i-reduced-my-dashboard-bundle-size-from-172-mb-to-299-kb-for-faster-loading-3gg5</link>
      <guid>https://forem.com/naufalyukafi/how-i-reduced-my-dashboard-bundle-size-from-172-mb-to-299-kb-for-faster-loading-3gg5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1mtglc1hjksfx54r6ki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1mtglc1hjksfx54r6ki.png" alt="Before Optimized Lazy Load" width="800" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As our product grew, the dashboard started feeling slower than expected, which impacted how quickly users could access key information and complete tasks. Longer load times risked frustrating users and reducing engagement. Looking into performance, I found the initial JavaScript bundle was 1.72 MB, which contributed to slower loading, especially on slower networks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even with React optimizations like React.memo and useCallback, first load performance can be overlooked. A large initial bundle affects user experience regardless of rendering optimizations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Optimize Imports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many components were loaded upfront, even if they weren’t immediately visible. Every large component added to the main bundle, increasing download size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Lazy Loading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The solution? React.lazy + Suspense. Lazy loading splits the code into chunks and loads components only when needed.&lt;/p&gt;

&lt;p&gt;Instead of importing components directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FrameworkProgress&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/dashboardWidget/FrameworkProgress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FrameworkProgress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/dashboardWidget/FrameworkProgress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmld3lt729vwvnbgwv7v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmld3lt729vwvnbgwv7v.png" alt="Example Full Code" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key points:&lt;/p&gt;

&lt;p&gt;React.lazy() loads components only when rendered.&lt;/p&gt;

&lt;p&gt;Suspense shows a fallback UI while loading.&lt;/p&gt;

&lt;p&gt;This reduces the initial bundle size and improves first load performance.&lt;/p&gt;

&lt;p&gt;The Result&lt;/p&gt;

&lt;p&gt;After applying lazy loading and optimizing imports:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before: 1.72 MB&lt;br&gt;
After: 296 KB&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02crr7hz7trt1e1zkc79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02crr7hz7trt1e1zkc79.png" alt="After Optimized Lazy Load" width="800" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dashboard now feels much faster, even on slower networks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First load size matters. Optimizations like memoization are useful, but bundle size impacts user experience directly.&lt;/p&gt;

&lt;p&gt;Lazy loading is simple but effective. React.lazy() + Suspense can dramatically improve performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Optimizing dashboard performance isn’t just about micro-optimizations inside React. Structuring code smartly and using lazy loading can significantly reduce bundle size and improve user experience.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>I Thought useRef Was Slow Until This Happened</title>
      <dc:creator>Naufal Yukafi Ridlo</dc:creator>
      <pubDate>Sun, 13 Apr 2025 04:33:54 +0000</pubDate>
      <link>https://forem.com/naufalyukafi/i-thought-useref-was-slow-until-this-happened-52oh</link>
      <guid>https://forem.com/naufalyukafi/i-thought-useref-was-slow-until-this-happened-52oh</guid>
      <description>&lt;p&gt;While coding with React, I almost never touched this particular React Hook: &lt;code&gt;useRef&lt;/code&gt;. Maybe it's more commonly used for controlling events like mouse interactions or similar. But here's the real question: &lt;strong&gt;why have I never used it in the past 2 years?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my mind:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's no way I'd skip learning a hook that's supposedly powerful if it was &lt;em&gt;that&lt;/em&gt; important.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I remembered that many of my developer friends often said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Be careful with useRef it can slow down your app."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe that's also why I thought:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Well then, no need to learn it if it's going to make things slow.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Until one day... I encountered a &lt;strong&gt;case at work&lt;/strong&gt; that &lt;strong&gt;forced&lt;/strong&gt; me to use &lt;code&gt;useRef&lt;/code&gt;. And surprisingly... the result was quite shocking in terms of performance!&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does &lt;code&gt;useRef&lt;/code&gt; Work?
&lt;/h2&gt;

&lt;p&gt;Under the hood, &lt;code&gt;useRef&lt;/code&gt; uses the &lt;strong&gt;JavaScript Closure&lt;/strong&gt; concept — allowing us to store data references outside the React render cycle. Simply put: a function can store and access data even when it's outside the render context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyiuh6sfn3w5yr4h2qgq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyiuh6sfn3w5yr4h2qgq9.png" alt="useRef React Hook" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/facebook/react/blob/39cad7afc43fcbca1fd2e3a0d5b7706c8b237793/packages/react-reconciler/src/ReactFiberHooks.js#L4068" rel="noopener noreferrer"&gt;React useRef Source Code&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;useRef&lt;/code&gt; stores an object like &lt;code&gt;{ current: ... }&lt;/code&gt; which is &lt;strong&gt;mutable&lt;/strong&gt; — it can be changed directly without triggering a re-render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Does &lt;code&gt;useRef&lt;/code&gt; Cause Slowness?
&lt;/h2&gt;

&lt;p&gt;Theoretically, &lt;strong&gt;no&lt;/strong&gt;, because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useRef&lt;/code&gt; doesn’t trigger a re-render like &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useEffect&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;ref.current&lt;/code&gt; is updated, React &lt;strong&gt;doesn’t care&lt;/strong&gt; or perform reconciliation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes &lt;code&gt;useRef&lt;/code&gt; &lt;strong&gt;efficient&lt;/strong&gt; — because it avoids the expensive re-rendering process.&lt;/p&gt;




&lt;h2&gt;
  
  
  React Rendering Process in Short
&lt;/h2&gt;

&lt;p&gt;To understand further, we need to grasp how &lt;strong&gt;React renders&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Component Initialization&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
React creates a component instance and executes it to produce React Elements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creating New Virtual DOM&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
React builds the Virtual DOM from the render result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Diffing Algorithm&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
React compares the new and old Virtual DOM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconciliation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
React identifies the changes and only updates the changed parts in the DOM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lifecycle &amp;amp; Side Effects&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Hooks like &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt; are executed after the DOM updates.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, &lt;code&gt;useState&lt;/code&gt; will retrigger this entire process when the value changes. But &lt;code&gt;useRef&lt;/code&gt;? No. Since it only stores references and doesn’t interact with the Virtual DOM — it’s &lt;strong&gt;much more efficient!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  So, Why Do People Say &lt;code&gt;useRef&lt;/code&gt; Can Be Slow?
&lt;/h2&gt;

&lt;p&gt;Back to the original question.&lt;/p&gt;

&lt;p&gt;The answer: &lt;strong&gt;potential memory leaks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React (and JavaScript in general) uses a &lt;strong&gt;garbage collector&lt;/strong&gt;. But if we carelessly store large data in a &lt;code&gt;ref&lt;/code&gt; without cleaning it up, that data &lt;strong&gt;won’t be cleared from memory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Eventually...&lt;br&gt;&lt;br&gt;
&lt;strong&gt;BOOM! Memory leak.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Real Case at My Office
&lt;/h2&gt;

&lt;p&gt;At work, I once had a case where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I had to handle &lt;strong&gt;HTML string input that could reach up to 5MB&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In our business logic, there was a refetch process in the code. Refetching could overwrite saved state if there was no external storage or isolated state. In this case, useRef became a solution since it’s not tied to the render lifecycle like useState.&lt;/li&gt;
&lt;li&gt;When I used &lt;code&gt;useRef&lt;/code&gt;, the input could be stored &lt;strong&gt;without triggering a re-render&lt;/strong&gt; and ran &lt;strong&gt;much faster&lt;/strong&gt;, because there was no need for expensive re-renders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However... when the &lt;code&gt;ref&lt;/code&gt; wasn't cleaned up properly, &lt;strong&gt;a memory leak occurred instantly.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// cleanup ref&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a simulation illustrating this situation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81fikala9p9s1vqiq2nw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81fikala9p9s1vqiq2nw.png" alt="Garbage Collector Simulation" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://codesandbox.io/p/sandbox/nsll4n" rel="noopener noreferrer"&gt;React useRef Real Case&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useRef&lt;/code&gt; is &lt;strong&gt;very useful&lt;/strong&gt;, especially for storing data that doesn’t need to trigger a re-render.&lt;/li&gt;
&lt;li&gt;But &lt;strong&gt;be cautious&lt;/strong&gt;: the data inside a &lt;code&gt;ref&lt;/code&gt; is not automatically cleaned up by React.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;useRef&lt;/code&gt; &lt;strong&gt;wisely&lt;/strong&gt;, especially when dealing with large data or many DOM references.&lt;/li&gt;
&lt;li&gt;Most importantly: &lt;strong&gt;understand the context&lt;/strong&gt; — don’t just avoid it because someone said it’s slow.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’re still confused, feel free to ask questions in the comments. And if there's any mistake in this article, I'm more than open to corrections 😊&lt;/p&gt;

</description>
      <category>react</category>
      <category>useref</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
