<?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>DEV Community: Darren Hwang</title>
    <description>The latest articles on DEV Community by Darren Hwang (@dhwang).</description>
    <link>https://dev.to/dhwang</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%2F610402%2Fc5b43a35-32ca-46b1-8990-8ddf3e87c90b.jpeg</url>
      <title>DEV Community: Darren Hwang</title>
      <link>https://dev.to/dhwang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhwang"/>
    <language>en</language>
    <item>
      <title>React Compiler and and the promise of automated memoization</title>
      <dc:creator>Darren Hwang</dc:creator>
      <pubDate>Fri, 15 May 2026 00:55:27 +0000</pubDate>
      <link>https://dev.to/dhwang/react-compiler-and-and-the-promise-of-automated-memoization-4g78</link>
      <guid>https://dev.to/dhwang/react-compiler-and-and-the-promise-of-automated-memoization-4g78</guid>
      <description>&lt;p&gt;The real-world impact of the &lt;a href="https://react.dev/learn/react-compiler" rel="noopener noreferrer"&gt;React Compiler&lt;/a&gt; (formerly React Forget). The promise of this tool is to automate memoization, theoretically freeing developers from the manual overhead of &lt;code&gt;useMemo&lt;/code&gt;, &lt;code&gt;useCallback&lt;/code&gt;, and &lt;code&gt;React.memo&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Manual Memoization
&lt;/h2&gt;

&lt;p&gt;React re-renders are cascading; a change in a parent component triggers a re-render for all children unless stopped by memoization. Manually implementing this is often complex and leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Referential instability:&lt;/strong&gt; Objects and functions recreated on every render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Prop drilling" complexity:&lt;/strong&gt; Tracing memoization through long component chains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messy code:&lt;/strong&gt; Over-use of hooks making the codebase unreadable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Compiler's Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Initial Load Performance
&lt;/h3&gt;

&lt;p&gt;One major concern was that memoizing "everything" would bloat the initial load. However, the tests showed &lt;strong&gt;minimal to no impact&lt;/strong&gt; on initial load times. The compiler is efficient enough that the overhead is negligible.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Interaction Performance
&lt;/h3&gt;

&lt;p&gt;The results here were mixed but generally positive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Case:&lt;/strong&gt; On a settings preview page, total blocking time dropped from &lt;strong&gt;280ms to 0ms&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realistic Case:&lt;/strong&gt; On a gallery page, blocking time dropped from &lt;strong&gt;130ms to 90ms&lt;/strong&gt;. The compiler eliminated many re-renders, but some heavy components still re-rendered due to unstable data references from external libraries (like &lt;a href="https://tanstack.com/query/latest" rel="noopener noreferrer"&gt;React Query&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Can it catch everything?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt; The investigation found the compiler failed to stop all re-renders in 7 out of 9 complex cases. Reasons include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incompatibility with certain external libraries.&lt;/li&gt;
&lt;li&gt;Legacy code structures the compiler doesn't yet understand.&lt;/li&gt;
&lt;li&gt;Non-primitive props (objects/arrays) that change references outside of the component's scope.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  React 18 Vs React 19
&lt;/h2&gt;

&lt;p&gt;React 18 made rendering smarter. React 19 improves performance more by reducing work the browser has to do, loading resources earlier, and making async updates feel faster. &lt;/p&gt;

&lt;p&gt;However, you have to opt-in to these improvements. It’s not that every render is magically faster; the biggest gains come from using the new React 19 patterns. &lt;/p&gt;

&lt;p&gt;React Compiler is often discussed with modern React because it can automatically memoize components and reduce unnecessary re-renders, but simply upgrading to React 19 does not automagically mean your app is using the compiler; it must be configured in your build setup.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Less JavaScript sent to the browser
&lt;/h4&gt;

&lt;p&gt;React 19 stabilizes Server Components, which let parts of your UI run on the server or at build time instead of in the browser. That means the user may download less JavaScript, parse less code, and see content sooner. React’s docs give an example where expensive markdown libraries are not included in the client bundle when moved into a Server Component. &lt;a href="https://react.dev/blog/2024/12/05/react-19" rel="noopener noreferrer"&gt;react.dev/react-19&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple analogy:&lt;/strong&gt;&lt;br&gt;
React 18 often ships more of the “kitchen” to the customer. React 19 can cook more on the server and only send the finished meal.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Better loading of CSS, scripts, fonts, and other resources
&lt;/h4&gt;

&lt;p&gt;React 19 adds better support for things like stylesheets, async scripts, and &lt;code&gt;preload&lt;/code&gt;/&lt;code&gt;preconnect&lt;/code&gt; APIs. This helps the browser discover important files earlier and avoid duplicated scripts or styles. React’s release notes specifically say these resource APIs can improve initial page loads and client-side navigations. &lt;a href="https://react.dev/blog/2024/12/05/react-19" rel="noopener noreferrer"&gt;react.dev/react-19&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React 19 gives you direct APIs (&lt;code&gt;preload&lt;/code&gt;, &lt;code&gt;preconnect&lt;/code&gt;, &lt;code&gt;preinit&lt;/code&gt;) to hint to the browser which fonts, scripts, or pages the user might need next. This makes navigation feel almost instant because resources are fetched ahead of time as soon as someone hovers over a link .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple example:&lt;/strong&gt;&lt;br&gt;
Instead of waiting until a component appears to discover its font or script, React can help the browser start fetching it earlier.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Smoother forms and async updates
&lt;/h4&gt;

&lt;p&gt;React 19 adds Actions, &lt;code&gt;useActionState&lt;/code&gt;, &lt;code&gt;useFormStatus&lt;/code&gt;, and &lt;code&gt;useOptimistic&lt;/code&gt;. These don’t necessarily make the CPU faster, but they make the app feel faster because React can show pending states and optimistic UI more naturally. For example, useOptimistic can immediately show the expected result while the server request is still running. &lt;a href="https://react.dev/blog/2024/12/05/react-19" rel="noopener noreferrer"&gt;react.dev/react-19&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple example:&lt;/strong&gt;&lt;br&gt;
You click “Save,” and the UI updates right away instead of waiting for the server to respond.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Better Suspense/data handling with use
&lt;/h4&gt;

&lt;p&gt;React 19’s use API lets components read promises during render and suspend until data is ready. Used with Suspense and frameworks, this can help avoid awkward loading flows and make async rendering more coordinated. &lt;a href="https://react.dev/blog/2024/12/05/react-19" rel="noopener noreferrer"&gt;react.dev/react-19&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple version:&lt;/strong&gt;&lt;br&gt;
React gets better at saying, “Pause this part until the data is ready, but keep the rest of the page moving.”&lt;/p&gt;

&lt;h4&gt;
  
  
  5. More resilient hydration
&lt;/h4&gt;

&lt;p&gt;Hydration is when React connects server-rendered HTML to interactive JavaScript in the browser. The initial hand‑off from server HTML to an interactive client app (hydration) is now twice as fast, meaning your app becomes usable much quicker after the page load. React 19 improves how hydration handles unexpected tags from third-party scripts or browser extensions, reducing cases where React has to throw away server HTML and re-render on the client. &lt;a href="https://react.dev/blog/2024/12/05/react-19" rel="noopener noreferrer"&gt;react.dev/react-19&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why that matters:&lt;/strong&gt;&lt;br&gt;
Less unnecessary re-rendering means fewer janky page loads.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Faster JSX transform requirement
&lt;/h4&gt;

&lt;p&gt;React 19 requires the modern JSX transform, which React says enables additional improvements including JSX speed improvements and faster performance. &lt;a href="https://react.dev/blog/2024/12/05/react-19" rel="noopener noreferrer"&gt;react.dev/react-19&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  7. An automatic “memoization” compiler
&lt;/h4&gt;

&lt;p&gt;In React 18, developers had to manually wrap things in &lt;code&gt;useMemo&lt;/code&gt; or &lt;code&gt;useCallback&lt;/code&gt; to avoid unnecessary re-renders. React 19 now includes a smart compiler that analyzes your components and handles this automatically—so you get fewer re-renders and snappier UIs without the extra boilerplate.&lt;/p&gt;

&lt;h4&gt;
  
  
  8. Concurrent rendering that just works
&lt;/h4&gt;

&lt;p&gt;React 18 introduced concurrent rendering but you had to opt in with things like &lt;code&gt;useTransition&lt;/code&gt;. React 19 makes this automatic—it instantly prioritizes urgent tasks (like typing or clicking) over less critical background work (like filtering a huge list), so the UI always feels responsive and never freezes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Important caveat
&lt;/h4&gt;

&lt;p&gt;React 19 is not simply &lt;em&gt;“React 18 but every render is faster.”&lt;/em&gt; React 18 already introduced major performance features like automatic batching, transitions, and streaming server rendering. (react.dev) React 19’s performance benefits mostly come when you use its newer architecture: Server Components, better resource loading, Actions, Suspense patterns, and modern tooling.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Again, React Compiler is often discussed with modern React because it can automatically memoize components and reduce unnecessary re-renders, but simply upgrading to React 19 does not automagically mean your app is using the compiler; it must be configured in your build setup. (react.dev)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bottom line:
&lt;/h2&gt;

&lt;p&gt;React 18 made updates smoother. React 19 helps apps load less, fetch smarter, hydrate more reliably, and feel faster during async work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️&lt;br&gt;
While the &lt;a href="https://react.dev/learn/react-compiler" rel="noopener noreferrer"&gt;React Compiler&lt;/a&gt; is a massive step forward, developers seeking to squeeze every millisecond of performance out of their apps will still need to understand and occasionally implement manual memoization.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Darren Hwang</dc:creator>
      <pubDate>Sun, 10 May 2026 01:17:21 +0000</pubDate>
      <link>https://dev.to/dhwang/-2ppl</link>
      <guid>https://dev.to/dhwang/-2ppl</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6" class="crayons-story__hidden-navigation-link"&gt;Preventing unnecessary re-renders using React.memo, useMemo and useCallback hooks&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/dhwang" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F610402%2Fc5b43a35-32ca-46b1-8990-8ddf3e87c90b.jpeg" alt="dhwang profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/dhwang" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Darren Hwang
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Darren Hwang
                
              
              &lt;div id="story-author-preview-content-3612114" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/dhwang" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F610402%2Fc5b43a35-32ca-46b1-8990-8ddf3e87c90b.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Darren Hwang&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 10&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6" id="article-link-3612114"&gt;
          Preventing unnecessary re-renders using React.memo, useMemo and useCallback hooks
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;7&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              4&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Preventing unnecessary re-renders using React.memo, useMemo and useCallback hooks</title>
      <dc:creator>Darren Hwang</dc:creator>
      <pubDate>Sun, 10 May 2026 01:11:10 +0000</pubDate>
      <link>https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6</link>
      <guid>https://dev.to/dhwang/preventing-unnecessary-re-renders-using-reactmemo-and-related-hooks-48f6</guid>
      <description>&lt;p&gt;Preventing unnecessary re-renders in React is crucial for maintaining performance, especially in complex component trees. Here is a comprehensive summary of the key concepts, focusing on &lt;code&gt;React.memo&lt;/code&gt; and related hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Re-renders
&lt;/h2&gt;

&lt;p&gt;When a parent component re-renders, its children automatically re-render as well. In large-scale applications, this default behavior can create noticeable performance bottlenecks.&lt;/p&gt;

&lt;p&gt;There are four primary reasons why a component will re-render itself, along with one common misconception.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. State Changes
&lt;/h3&gt;

&lt;p&gt;This is the "root" source of all re-renders. When a component’s state is updated (typically via &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useReducer&lt;/code&gt;), the component triggers a re-render to reflect the new data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trigger:&lt;/strong&gt; Usually happens inside event callbacks or &lt;code&gt;useEffect&lt;/code&gt; hooks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Parent Re-renders
&lt;/h3&gt;

&lt;p&gt;If a parent component re-renders, React will automatically re-render all of its children.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Direction:&lt;/strong&gt; The render cycle always flows "down" the tree. A child re-rendering does not naturally trigger a parent re-render unless it invokes a state change in that parent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Context Changes
&lt;/h3&gt;

&lt;p&gt;When the value provided by a &lt;code&gt;Context.Provider&lt;/code&gt; changes, &lt;strong&gt;every&lt;/strong&gt; component consuming that context will re-render.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; This occurs even if the component only utilizes a portion of the data that &lt;em&gt;didn't&lt;/em&gt; change. These re-renders cannot be prevented with simple memoization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Hook Changes
&lt;/h3&gt;

&lt;p&gt;Since everything inside a custom hook belongs to the component utilizing it, standard rules for state and context apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A state change inside a hook triggers a re-render of the "host" component.&lt;/li&gt;
&lt;li&gt;If a hook consumes a Context that changes, the "host" component re-renders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⛔ The "Props Change" Myth
&lt;/h3&gt;

&lt;p&gt;A prevalent misconception is that a component re-renders &lt;em&gt;because&lt;/em&gt; its props changed. In reality, for props to change, the parent must re-render first.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a component is &lt;strong&gt;not memoized&lt;/strong&gt;, it will re-render when its parent does, regardless of whether the props are identical or entirely different.&lt;/li&gt;
&lt;li&gt;Props only become the deciding factor for a re-render when using memoization techniques like &lt;a href="https://www.developerway.com/posts/react-re-renders-guide%23preventing-re-renders-with-react.memo" rel="noopener noreferrer"&gt;React.memo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Re-render Triggers
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The component's internal &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useReducer&lt;/code&gt; was updated.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The component's parent is re-rendering.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;useContext&lt;/code&gt; value the component subscribes to has changed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hooks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A state or context change occurred inside a hook used by the component.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Using React.memo
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt; is a higher-order component that memoizes a child component. It intercepts the default behavior and prevents re-renders if the component's incoming props have not changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pitfall: Referential Equality
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt; relies on shallow comparison. Objects can cause unintended re-renders because of how React compares props—specifically through referential equality.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Referential Equality:&lt;/strong&gt; For primitive values (strings, numbers, booleans), React compares the actual value. However, for objects, arrays, and functions, it compares the memory reference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New References on Render:&lt;/strong&gt; Every time a parent component re-renders, any prop defined inline (e.g., &lt;code&gt;user={{ id: 1 }}&lt;/code&gt;) is recreated as a brand-new object in memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Effect:&lt;/strong&gt; Because this new object has a different reference than the one from the previous render, React assumes the prop has changed. Even if the child is wrapped in &lt;code&gt;React.memo&lt;/code&gt;, it will ignore the memoization and re-render because the shallow comparison returns &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Solution: &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To prevent this broken memoization, you must preserve the object or function's reference across re-renders.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;useMemo&lt;/code&gt; hook to cache objects and arrays.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;useCallback&lt;/code&gt; hook to cache functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom Comparison
&lt;/h3&gt;

&lt;p&gt;Similar to the legacy &lt;code&gt;shouldComponentUpdate&lt;/code&gt; lifecycle method in class components, you can pass a custom comparison function as the second argument to &lt;code&gt;React.memo&lt;/code&gt;. This allows you to define the exact logic for when a component should update.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;Optimization should always be a "last resort." Prioritize solid component composition techniques first (like moving state down or passing elements as &lt;code&gt;children&lt;/code&gt;). Composition is generally more predictable and maintainable than adding complex layers of memoization hooks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Based on the &lt;a href="https://www.developerway.com/posts/react-re-renders-guide" rel="noopener noreferrer"&gt;React re-renders guide&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>requestAnimationFrame vs requestIdleCallback</title>
      <dc:creator>Darren Hwang</dc:creator>
      <pubDate>Mon, 06 Apr 2026 18:41:02 +0000</pubDate>
      <link>https://dev.to/dhwang/requestanimationframe-vs-requestidlecallback-1m8c</link>
      <guid>https://dev.to/dhwang/requestanimationframe-vs-requestidlecallback-1m8c</guid>
      <description>&lt;p&gt;The primary difference between  (rAF) and  (rIC) is priority and timing within the browser's event loop. &lt;br&gt;
Key Differences &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;(rAF)&lt;/th&gt;
&lt;th&gt;(rIC)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Priority&lt;/td&gt;
&lt;td&gt;High: Critical for visual updates.&lt;/td&gt;
&lt;td&gt;Low: Non-critical background tasks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing&lt;/td&gt;
&lt;td&gt;Executes before the next repaint/refresh.&lt;/td&gt;
&lt;td&gt;Executes during idle periods at the end of a frame.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frequency&lt;/td&gt;
&lt;td&gt;Matches display refresh rate (usually 60Hz).&lt;/td&gt;
&lt;td&gt;Unpredictable; depends on CPU availability.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best For&lt;/td&gt;
&lt;td&gt;Animations, UI transitions, and DOM changes.&lt;/td&gt;
&lt;td&gt;Analytics, background data processing, or logging.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser Support&lt;/td&gt;
&lt;td&gt;Universal support across all modern browsers.&lt;/td&gt;
&lt;td&gt;Not supported in Safari; experimental in others.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Detailed Comparison
&lt;/h2&gt;
&lt;h3&gt;
  
  
  requestAnimationFrame
&lt;/h3&gt;

&lt;p&gt;• Synchronization: It synchronizes your code with the browser's V-Sync, ensuring that visual changes happen exactly once per frame to prevent "jank" or screen tearing. &lt;br&gt;
• Power Efficiency: If the tab is backgrounded or hidden, the browser automatically pauses rAF calls to save battery and CPU. &lt;br&gt;
• Usage: Ideal for any task that modifies the DOM or CSS styles for visual feedback. &lt;/p&gt;
&lt;h3&gt;
  
  
  requestIdleCallback
&lt;/h3&gt;

&lt;p&gt;• Idle Deadline: It provides a  object with a  method, allowing you to check how many milliseconds are left before the browser needs to process higher-priority tasks. &lt;br&gt;
• Guaranteed Execution: You can pass an optional  (e.g., ) to force the browser to run the task even if it never becomes idle. &lt;br&gt;
• Restrictions: You should not modify the DOM inside rIC, as it occurs after the frame's layout and paint phases; doing so can cause expensive reflows in the next frame. &lt;/p&gt;
&lt;h3&gt;
  
  
  When to use which?
&lt;/h3&gt;

&lt;p&gt;• Use requestAnimationFrame when you need to update the UI or perform an animation. &lt;br&gt;
• Use requestIdleCallback for background tasks like sending telemetry, pre-fetching data, or non-urgent state calculations that shouldn't interrupt user interaction. &lt;/p&gt;
&lt;h2&gt;
  
  
  rAF, rIC and Deferred Value
&lt;/h2&gt;

&lt;p&gt;Use requestAnimationFrame (rAF) or requestIdleCallback (rIC) serve different performance goals compared to the built-in useDeferredValue hook. [1]  &lt;/p&gt;
&lt;h2&gt;
  
  
  Choosing the Right API
&lt;/h2&gt;

&lt;p&gt;• requestAnimationFrame (rAF): Best for visual synchronization. It ensures the value updates just before the next browser repaint (typically every 16.67ms), preventing visual stuttering during high-frequency updates like scrolling or resizing. &lt;br&gt;
• requestIdleCallback (rIC): Best for non-urgent background work. It waits until the browser is completely idle before updating the value, which avoids interfering with critical user interactions like typing. &lt;br&gt;
• useDeferredValue (React Built-in): If you are on React 18+, this is usually superior because it integrates with React's Concurrent Mode. It schedules a low-priority background render that is interruptible if a new update occurs. [2, 3, 4, 5, 6, 7]  &lt;/p&gt;
&lt;h3&gt;
  
  
  Implementation Guidelines
&lt;/h3&gt;

&lt;p&gt;When implementing these in a custom hook, follow these patterns to ensure stability: &lt;/p&gt;

&lt;p&gt;• Use  for IDs: Store the request ID returned by rAF/rIC in a useRef to track and cancel it during cleanup. &lt;br&gt;
• Cleanup on Unmount: Always return a cleanup function in  to call  or  to prevent memory leaks and "ghost" state updates. &lt;br&gt;
• Throttle State Updates: Be cautious with state updates inside these callbacks. High-refresh-rate displays (120Hz+) can trigger rAF more frequently than needed, potentially causing performance overhead if not throttled. &lt;br&gt;
• Browser Compatibility: While rAF is widely supported, requestIdleCallback is not supported in all browsers (e.g., older Safari versions). Use a polyfill or a  fallback for production apps. [3, 8, 9, 10, 11, 12]&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;let&lt;/span&gt; &lt;span class="nx"&gt;fps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;lastTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;fps&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="c1"&gt;// Skip frame if too early&lt;/span&gt;

  &lt;span class="nx"&gt;lastTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;fps&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// Perform throttled work&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Summary Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary Goal&lt;/td&gt;
&lt;td&gt;Smooth animations/visuals&lt;/td&gt;
&lt;td&gt;Background/Low-priority tasks&lt;/td&gt;
&lt;td&gt;Non-blocking UI updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution Timing&lt;/td&gt;
&lt;td&gt;Before next repaint&lt;/td&gt;
&lt;td&gt;During browser idle time&lt;/td&gt;
&lt;td&gt;React's idle time (interruptible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best For&lt;/td&gt;
&lt;td&gt;Position/Layout updates&lt;/td&gt;
&lt;td&gt;Analytics, heavy data processing&lt;/td&gt;
&lt;td&gt;Expensive list rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React Integration&lt;/td&gt;
&lt;td&gt;Manual (via )&lt;/td&gt;
&lt;td&gt;Manual (via )&lt;/td&gt;
&lt;td&gt;Native (Concurrent Mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;[1] &lt;a href="https://layonez.medium.com/performant-animations-with-requestanimationframe-and-react-hooks-99a32c5c9fbf" rel="noopener noreferrer"&gt;https://layonez.medium.com/performant-animations-with-requestanimationframe-and-react-hooks-99a32c5c9fbf&lt;/a&gt;&lt;br&gt;
[2] &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame&lt;/a&gt;&lt;br&gt;
[3] &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback&lt;/a&gt;&lt;br&gt;
[4] &lt;a href="https://en.blog.jasonzk.com/js/requestidlecallback-and-requestanimationframe/" rel="noopener noreferrer"&gt;https://en.blog.jasonzk.com/js/requestidlecallback-and-requestanimationframe/&lt;/a&gt;&lt;br&gt;
[6] &lt;a href="https://www.youtube.com/watch?v=yIpHTYo3PY0" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=yIpHTYo3PY0&lt;/a&gt;&lt;br&gt;
[10] &lt;a href="https://dev.to/tawe/requestanimationframe-explained-why-your-ui-feels-laggy-and-how-to-fix-it-3ep2"&gt;https://dev.to/tawe/requestanimationframe-explained-why-your-ui-feels-laggy-and-how-to-fix-it-3ep2&lt;/a&gt;&lt;br&gt;
[11] &lt;a href="https://github.com/Chalarangelo/30-seconds-of-code/blob/master/content/snippets/react/s/use-request-animation-frame.md" rel="noopener noreferrer"&gt;https://github.com/Chalarangelo/30-seconds-of-code/blob/master/content/snippets/react/s/use-request-animation-frame.md&lt;/a&gt;&lt;br&gt;
[12] &lt;a href="https://css-tricks.com/using-requestanimationframe-with-react-hooks/" rel="noopener noreferrer"&gt;https://css-tricks.com/using-requestanimationframe-with-react-hooks/&lt;/a&gt;&lt;br&gt;
[13] &lt;a href="https://stackoverflow.com/questions/38709923/why-is-requestanimationframe-better-than-setinterval-or-settimeout" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/38709923/why-is-requestanimationframe-better-than-setinterval-or-settimeout&lt;/a&gt;&lt;br&gt;
[14] &lt;a href="https://medium.com/@ignatovich.dm/understanding-usedeferredvalue-in-react-enhancing-performance-with-deferred-rendering-ec8eb28aa997" rel="noopener noreferrer"&gt;https://medium.com/@ignatovich.dm/understanding-usedeferredvalue-in-react-enhancing-performance-with-deferred-rendering-ec8eb28aa997&lt;/a&gt;&lt;br&gt;
[15] &lt;a href="https://medium.com/zestgeek/understanding-reacts-usedeferredvalue-hook-a-comprehensive-guide-with-examples-f8aa3361ee23" rel="noopener noreferrer"&gt;https://medium.com/zestgeek/understanding-reacts-usedeferredvalue-hook-a-comprehensive-guide-with-examples-f8aa3361ee23&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2] &lt;a href="https://macarthur.me/posts/navigating-the-event-loop/" rel="noopener noreferrer"&gt;https://macarthur.me/posts/navigating-the-event-loop/&lt;/a&gt;&lt;br&gt;
[3] &lt;a href="https://developer.chrome.com/blog/using-requestidlecallback" rel="noopener noreferrer"&gt;https://developer.chrome.com/blog/using-requestidlecallback&lt;/a&gt;&lt;br&gt;
[4] &lt;a href="https://www.luisball.com/blog/request-animation-frame-versus-request-idle-callback" rel="noopener noreferrer"&gt;https://www.luisball.com/blog/request-animation-frame-versus-request-idle-callback&lt;/a&gt;&lt;br&gt;
[5] &lt;a href="https://stackoverflow.com/questions/61145102/using-requestanimationframe-inside-requestidlecallback" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/61145102/using-requestanimationframe-inside-requestidlecallback&lt;/a&gt;&lt;br&gt;
[6] &lt;a href="https://powerfulyang.com/post/104" rel="noopener noreferrer"&gt;https://powerfulyang.com/post/104&lt;/a&gt;&lt;br&gt;
[7] &lt;a href="https://andriii.hashnode.dev/windowrequestidlecallback-all-you-need-to-know" rel="noopener noreferrer"&gt;https://andriii.hashnode.dev/windowrequestidlecallback-all-you-need-to-know&lt;/a&gt;&lt;br&gt;
[10] &lt;a href="https://www.clicktorelease.com/blog/calculating-fps-with-requestIdleCallback/" rel="noopener noreferrer"&gt;https://www.clicktorelease.com/blog/calculating-fps-with-requestIdleCallback/&lt;/a&gt;&lt;br&gt;
[11] &lt;a href="https://andriii.hashnode.dev/requestanimationframe-all-you-need-to-know" rel="noopener noreferrer"&gt;https://andriii.hashnode.dev/requestanimationframe-all-you-need-to-know&lt;/a&gt;&lt;br&gt;
[12] &lt;a href="https://dev.to/sylwia-lask/9-things-youre-overengineering-the-browser-already-solved-them-o99"&gt;https://dev.to/sylwia-lask/9-things-youre-overengineering-the-browser-already-solved-them-o99&lt;/a&gt;&lt;br&gt;
[13] &lt;a href="https://dev.to/codewithrajat/boost-your-web-performance-mastering-javascript-scheduling-methods-56eh"&gt;https://dev.to/codewithrajat/boost-your-web-performance-mastering-javascript-scheduling-methods-56eh&lt;/a&gt;&lt;br&gt;
[15] &lt;a href="https://caniuse.com/requestidlecallback" rel="noopener noreferrer"&gt;https://caniuse.com/requestidlecallback&lt;/a&gt;&lt;br&gt;
[16] &lt;a href="https://www.youtube.com/watch?v=oDYT2J5zNHc" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=oDYT2J5zNHc&lt;/a&gt;&lt;br&gt;
[17] &lt;a href="https://medium.com/imgcook/a-closer-look-at-react-fiber-b2ab072fcc2a" rel="noopener noreferrer"&gt;https://medium.com/imgcook/a-closer-look-at-react-fiber-b2ab072fcc2a&lt;/a&gt;&lt;br&gt;
[18] &lt;a href="https://www.youtube.com/watch?v=nect7xrF2go" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=nect7xrF2go&lt;/a&gt;&lt;br&gt;
[19] &lt;a href="https://www.debugbear.com/blog/requestanimationframe" rel="noopener noreferrer"&gt;https://www.debugbear.com/blog/requestanimationframe&lt;/a&gt;&lt;br&gt;
[20] &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/CSS_JavaScript_animation_performance" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/CSS_JavaScript_animation_performance&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The most powerful pattern in TypeScript, Discriminated Unions</title>
      <dc:creator>Darren Hwang</dc:creator>
      <pubDate>Mon, 06 Apr 2026 18:19:42 +0000</pubDate>
      <link>https://dev.to/dhwang/the-most-powerful-patterns-in-typescript-discriminated-unions-2inb</link>
      <guid>https://dev.to/dhwang/the-most-powerful-patterns-in-typescript-discriminated-unions-2inb</guid>
      <description>&lt;p&gt;Discriminated Unions is useful in cases where you have a discriminant, which is a common property with a literal type (like 'idle', 'loading') that exists in every member.&lt;/p&gt;

&lt;p&gt;TypeScript will narrow the type based on the discriminator, a common property to discriminate between union members. , making your code much safer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// TypeScript knows state is { status: 'idle' }&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// TypeScript knows state is { status: 'loading' }&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// TypeScript knows state has 'data' property&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// TypeScript knows state has 'error' property&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_exhaustive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unhandled status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;The most powerful patterns in TypeScript. &lt;strong&gt;Discriminated Unions&lt;/strong&gt; allow you to create a type-safe state machine where the compiler ensures you only access data that actually exists in a given state.&lt;/p&gt;

&lt;p&gt;Here is a breakdown of why this pattern is the gold standard for state management.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Core Components
&lt;/h2&gt;

&lt;p&gt;To create a Discriminated Union, you need three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Members:&lt;/strong&gt; Individual object types representing different states.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Discriminant:&lt;/strong&gt; A common property with a &lt;strong&gt;literal type&lt;/strong&gt; (like &lt;code&gt;'idle'&lt;/code&gt;, &lt;code&gt;'loading'&lt;/code&gt;) that exists in every member.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Union:&lt;/strong&gt; A type that combines them using the &lt;code&gt;|&lt;/code&gt; operator.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example Anatomy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// 'data' only exists here&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;   &lt;span class="c1"&gt;// 'error' only exists here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Why It Beats "Optional Property" Hell
&lt;/h2&gt;

&lt;p&gt;Without unions, developers often use one giant object with optional properties. This is dangerous because it allows for "impossible states."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The "Bad" Way (Optional Properties)&lt;/th&gt;
&lt;th&gt;The "Good" Way (Discriminated Unions)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data?: string; error?: Error;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data and Error are tied to specific statuses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You could accidentally have both &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; at the same time.&lt;/td&gt;
&lt;td&gt;The type system makes it impossible to have &lt;code&gt;data&lt;/code&gt; while in an &lt;code&gt;error&lt;/code&gt; state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires constant null checks or "non-null assertions" (&lt;code&gt;!&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;TypeScript &lt;strong&gt;narrows&lt;/strong&gt; the type automatically.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3. Type Narrowing in Action
&lt;/h2&gt;

&lt;p&gt;As you showed in your post's &lt;code&gt;switch&lt;/code&gt; statement, once you check the &lt;code&gt;status&lt;/code&gt; property, TypeScript "narrows" the object to that specific member of the union.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&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;span class="c1"&gt;// Inside this block, TypeScript knows 'data' exists.&lt;/span&gt;
    &lt;span class="c1"&gt;// You don't need to check if state.data is undefined.&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;h2&gt;
  
  
  4. Exhaustiveness Checking
&lt;/h2&gt;

&lt;p&gt;One of the best "pro tips" for state management is ensuring you've handled every possible state. You can use the &lt;code&gt;never&lt;/code&gt; type to catch unhandled cases at compile time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Waiting...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// If you add a new state like 'processing' later, &lt;/span&gt;
      &lt;span class="c1"&gt;// TypeScript will throw an error here because 'processing'&lt;/span&gt;
      &lt;span class="c1"&gt;// cannot be assigned to 'never'.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_exhaustiveCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_exhaustiveCheck&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;h3&gt;
  
  
  Summary of Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Safety:&lt;/strong&gt; Prevents accessing &lt;code&gt;data&lt;/code&gt; when the app is still &lt;code&gt;loading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clarity:&lt;/strong&gt; The code serves as documentation for what data is available when.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability:&lt;/strong&gt; Adding a new state (e.g., &lt;code&gt;reconnecting&lt;/code&gt;) triggers compiler errors in every function that hasn't accounted for it yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Further reading and references
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shayy/20-typescript-tricks-every-developer-should-know-94c"&gt;https://dev.to/shayy/20-typescript-tricks-every-developer-should-know-94c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/maryanmats/stop-using-booleans-everywhere-use-union-types-instead-k9m"&gt;https://dev.to/maryanmats/stop-using-booleans-everywhere-use-union-types-instead-k9m&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Learning CacheStorage</title>
      <dc:creator>Darren Hwang</dc:creator>
      <pubDate>Thu, 12 May 2022 19:03:42 +0000</pubDate>
      <link>https://dev.to/dhwang/learning-cachestorage-12c7</link>
      <guid>https://dev.to/dhwang/learning-cachestorage-12c7</guid>
      <description>&lt;p&gt;Just learned about CacheStorage, will try experiment with it. Seems promising&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
