<?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: Maria Kim</title>
    <description>The latest articles on DEV Community by Maria Kim (@mariahello).</description>
    <link>https://dev.to/mariahello</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%2F820597%2Fd83679f8-f169-40c7-ba5b-20273f6aba40.jpeg</url>
      <title>DEV Community: Maria Kim</title>
      <link>https://dev.to/mariahello</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mariahello"/>
    <language>en</language>
    <item>
      <title>Perfecting the Loading Experience with next/dynamic and React Suspense</title>
      <dc:creator>Maria Kim</dc:creator>
      <pubDate>Mon, 17 Mar 2025 05:22:11 +0000</pubDate>
      <link>https://dev.to/mariahello/perfecting-the-loading-experience-with-nextdynamic-and-react-suspense-8jp</link>
      <guid>https://dev.to/mariahello/perfecting-the-loading-experience-with-nextdynamic-and-react-suspense-8jp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In Next.js, you can speed up your app and provide a better user experience by &lt;strong&gt;lazy loading&lt;/strong&gt; components. The official docs for &lt;a href="https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#nextdynamic" rel="noopener noreferrer"&gt;next/dynamic&lt;/a&gt; describe it as a “composite of React.lazy() and Suspense.” &lt;/p&gt;

&lt;p&gt;However, in practice, it differs in a few important ways—especially when data fetching is involved. Let’s dive in and see how next/dynamic works, why you’d combine it with React Suspense, and what really happens during server and client rendering.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. next/dynamic in a Nutshell
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-Only Execution&lt;/strong&gt;: Even if your component has 'use client', Next.js &lt;strong&gt;still attempts&lt;/strong&gt; a minimal server render (generating some HTML) unless you explicitly disable SSR with ssr: false. Using next/dynamic with ssr: false forces the component to only render on the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Loading&lt;/strong&gt;: It &lt;strong&gt;splits the bundle&lt;/strong&gt;, loading the component only when needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Loading UI&lt;/strong&gt;: The loading option provides a &lt;strong&gt;placeholder&lt;/strong&gt; while the imported component is being downloaded from the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LazyLoadedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&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="s1"&gt;./MyComponent&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="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading component...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup, Next.js will &lt;strong&gt;not&lt;/strong&gt; server-render MyComponent; it sends a minimal placeholder to the browser. Only once the JavaScript for MyComponent is downloaded does it render.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. next/dynamic vs. React.lazy() and Suspense
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The docs mention&lt;/strong&gt;: “next/dynamic is a composite of React.lazy() and Suspense.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reality&lt;/strong&gt;: While next/dynamic harnesses a similar underlying mechanism to chunk-split components, it does not automatically suspend on data-fetching Promises. Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you’re fetching data within a dynamically imported component (e.g., using React Query’s useSuspenseQuery), React Suspense needs to handle that &lt;strong&gt;separately&lt;/strong&gt; from the dynamic import’s loading UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, you might still see two different loading states if you’re not careful:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One for &lt;strong&gt;component import&lt;/strong&gt; (handled by next/dynamic loading).&lt;/li&gt;
&lt;li&gt;Another for &lt;strong&gt;data loading&lt;/strong&gt; (handled by Suspense fallback when your data-fetching hook suspends).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Why Use Suspense at All?
&lt;/h2&gt;

&lt;p&gt;React Suspense provides a &lt;strong&gt;unified way&lt;/strong&gt; to handle asynchronous operations, such as &lt;strong&gt;data fetching&lt;/strong&gt; or &lt;strong&gt;component loading&lt;/strong&gt;. If your dynamically imported components also fetch data with Suspense-friendly libraries (like React Query’s &lt;code&gt;useSuspenseQuery&lt;/code&gt;), you can wrap them in a  boundary to have a single fallback UI for both component loading and data loading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&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="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/dynamic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useClientStore&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="s1"&gt;@/providers/client-store-provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PantryBoxesSkeleton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./PantryBoxes/PantryBoxesSkeleton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Forcing client-only rendering and a placeholder while the import downloads&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GuestUserPantry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&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="s1"&gt;./GuestUserPantry&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="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PantryBoxesSkeleton&lt;/span&gt;&lt;span class="p"&gt;,&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;LogInUserPantry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&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="s1"&gt;./LogInUserPantry&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="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PantryBoxesSkeleton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Pantry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Example: Zustand store check&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useClientStore&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="o"&gt;=&amp;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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Dynamically pick the right component&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;LogInUserPantry&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GuestUserPantry&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PantryBoxesSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PantryBoxesSkeleton&lt;/code&gt; is shown &lt;strong&gt;while the component is being dynamically imported&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;GuestUserPantry&lt;/code&gt; or &lt;code&gt;LogInUserPantry&lt;/code&gt; suspends while fetching data,  falls back to &lt;code&gt;PantryBoxesSkeleton&lt;/code&gt; again until data resolves.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;result&lt;/strong&gt; is a single consistent skeleton UI, avoiding multiple flickering loaders.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Key Takeaways &amp;amp; Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use next/dynamic for True Client-Only Components&lt;/strong&gt;&lt;br&gt;
Setting ssr: false ensures Next.js doesn’t attempt to render on the server at all, especially handy for code that is purely browser-specific (e.g., accessing window or localStorage).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Combine next/dynamic with Suspense for Seamless Fallback&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;loading in next/dynamic covers the import phase.&lt;/li&gt;
&lt;li&gt;Suspense fallback covers data fetching or any other asynchronous tasks in the child component.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Beware of Double Loading States&lt;/strong&gt;&lt;br&gt;
If you don’t unify your placeholders, users might see one loading UI for dynamic imports and another loading state for data fetching. Reuse the same fallback wherever possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understand That next/dynamic and React.lazy() Differ&lt;/strong&gt;&lt;br&gt;
Even though the docs liken them, next/dynamic is a Next.js abstraction that doesn’t automatically tie into Suspense’s data-fetching logic. They can work together, but they address different parts of the lazy-loading process.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;While Next.js’s next/dynamic is often described as a “composite” of React.lazy() and Suspense, it &lt;strong&gt;does not&lt;/strong&gt; handle data-fetching Promises the way Suspense does. Instead, it’s best to &lt;strong&gt;use both&lt;/strong&gt;: let next/dynamic handle component-level lazy-loading, and let &lt;strong&gt;React Suspense&lt;/strong&gt; handle asynchronous data loading behind the scenes. This dual approach ensures a &lt;strong&gt;consistent loading placeholder&lt;/strong&gt; and &lt;strong&gt;a smoother user experience&lt;/strong&gt;—with minimal flickers and streamlined hydration on the client.&lt;/p&gt;




&lt;p&gt;That’s it! By combining next/dynamic (with ssr: false) and React Suspense, you’ll avoid any “double loading” confusion and deliver a polished, high-performance Next.js application. Happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Next.js — Can we make an Intercepting Route behave like ISR?</title>
      <dc:creator>Maria Kim</dc:creator>
      <pubDate>Tue, 25 Feb 2025 11:51:19 +0000</pubDate>
      <link>https://dev.to/mariahello/nextjs-can-we-make-an-intercepting-route-behave-like-isr-3e35</link>
      <guid>https://dev.to/mariahello/nextjs-can-we-make-an-intercepting-route-behave-like-isr-3e35</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%2Frpq2s8mgjtcdguhrt1gf.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%2Frpq2s8mgjtcdguhrt1gf.png" alt="Next.js" width="420" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Definitions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Incremental Static Regeneration
&lt;/h3&gt;

&lt;p&gt;• Closely related to &lt;strong&gt;SSG&lt;/strong&gt; and pages that are revalidated either at build time or at runtime.&lt;br&gt;
• Lets you update static content without having to rebuild your entire site.&lt;br&gt;
• Reduces server load by serving most requests with pre-rendered static pages.&lt;br&gt;
• Automatically applies proper cache-control headers to pages.&lt;br&gt;
• The value specified in revalidate will automatically be applied to any fetch calls in the page as the cache-control revalidate value.&lt;br&gt;
• ⚠️ &lt;strong&gt;However, if you set fetch to use the force-cache option, the automatic setting is ignored.&lt;/strong&gt; In that case, you need to manually specify the revalidate option.&lt;br&gt;
• Lets you handle large numbers of pages without incurring a long next build time.&lt;br&gt;
• If you add generateStaticParams, then dynamicParams is automatically set to true.&lt;br&gt;
• During the build, only the pages for parameters defined in generateStaticParams are generated.&lt;br&gt;
• If a request comes in at runtime with a parameter that wasn't included in generateStaticParams, the page will be generated at that time and revalidation will be applied.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration" rel="noopener noreferrer"&gt;Next.js Docs - ISR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate" rel="noopener noreferrer"&gt;Next.js Docs - revalidate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams" rel="noopener noreferrer"&gt;Next.js Docs - dynamicParams&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What are Intercepting Routes?
&lt;/h3&gt;

&lt;p&gt;• Designed to dynamically load content.&lt;br&gt;
• Allows you to show new content without leaving the current layout or navigating to a different route.&lt;br&gt;
• Because of that, &lt;strong&gt;Intercepting Routes cannot be used with ISR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes" rel="noopener noreferrer"&gt;Next.js Docs - Intercepting Routes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  How Does Next.js Handle Caching?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Caching Types
&lt;/h3&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%2Faeqsnwczwufyjpn1dxie.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%2Faeqsnwczwufyjpn1dxie.png" alt="Next.js cache" width="800" height="589"&gt;&lt;/a&gt;&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%2Ffcxgrb6mbidcus9touz7.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%2Ffcxgrb6mbidcus9touz7.png" alt="Next.js cache" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next.js has different caching layers:&lt;/p&gt;

&lt;p&gt;• Persistent (but revalidatable) server-based caches include the &lt;strong&gt;Full Route Cache&lt;/strong&gt; and the &lt;strong&gt;Data Cache&lt;/strong&gt;.&lt;br&gt;
• However, the &lt;strong&gt;Full Route Cache&lt;/strong&gt; requires storing HTML and RSC payloads. That means it is generally used when an actual route can be cached, like with SSG or ISR.&lt;br&gt;
• So if you want to cache responses in a way similar to SSG/ISR (for incoming requests), your only option is the &lt;strong&gt;Data Cache&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/building-your-application/caching#data-cache" rel="noopener noreferrer"&gt;Next.js Docs - Caching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Question
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can we make an Intercepting Route behave like ISR?&lt;/strong&gt;&lt;br&gt;
• &lt;strong&gt;Is it possible to use ISR for Intercepting Routes?&lt;/strong&gt;&lt;br&gt;
As noted above, Intercepting Routes only alter the address within the current layout rather than serving an entirely separate page route. Therefore, they &lt;strong&gt;cannot&lt;/strong&gt; be cached as an ISR page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• What does "behave like ISR" really mean?&lt;br&gt;
In many cases, it means:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Caching data as much as possible.&lt;/li&gt;
&lt;li&gt;Using the latest data after a specified interval.
Let's look into how we can address these requirements.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The Core Issues to Solve
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Caching data as much as possible**
&lt;/h4&gt;

&lt;p&gt;Revisiting the available caches in Next.js, we can categorize them by storage location and lifespan:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Server + Persistent (revalidatable)&lt;/strong&gt;&lt;br&gt;
• Full Route Cache&lt;br&gt;
• Data Cache&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Server + Within a single request&lt;/strong&gt;&lt;br&gt;
• Request Memoization&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Client-Side&lt;/strong&gt;&lt;br&gt;
• Router Cache&lt;/p&gt;

&lt;p&gt;The caches that live on the server and can persist across multiple requests are &lt;strong&gt;Full Route Cache and Data Cache&lt;/strong&gt;. However, because Full Route Cache stores the HTML/RSC for entire pages (as with SSG/ISR), that option isn't suitable for Intercepting Routes.&lt;/p&gt;

&lt;p&gt;That leaves the &lt;strong&gt;Data Cache&lt;/strong&gt; as our tool of choice.&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Using fresh data at a specified interval
&lt;/h4&gt;

&lt;p&gt;To leverage Data Cache, you can use the fetch option in Next.js:&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&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="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;force-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;revalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 1 day in seconds&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, you set the cache behavior to force-cache, and specify a revalidate interval (in seconds) within the next property. This allows Next.js to revalidate your data cache at the given interval, effectively mimicking the "ISR-like" behavior of periodically refreshing your data - without actually using a separate ISR route.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/building-your-application/caching#data-cache" rel="noopener noreferrer"&gt;Next.js Docs - Caching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That's how you can approximate ISR-like caching and revalidation for Intercepting Routes. While you can't truly make them into ISR pages, you can still benefit from Next.js's Data Cache to cache and periodically refresh the data used within those routes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Using Emotion in a New Project: Component Inheritance vs. Single Styled Component with Props</title>
      <dc:creator>Maria Kim</dc:creator>
      <pubDate>Tue, 25 Feb 2025 11:31:51 +0000</pubDate>
      <link>https://dev.to/mariahello/using-emotion-in-a-new-project-component-inheritance-vs-single-styled-component-with-props-2o1l</link>
      <guid>https://dev.to/mariahello/using-emotion-in-a-new-project-component-inheritance-vs-single-styled-component-with-props-2o1l</guid>
      <description>&lt;p&gt;I was creating shared (common) components using &lt;strong&gt;Emotion&lt;/strong&gt; in a new project. As I was considering how best to structure things for cleanliness and scalability, I happened to watch a YouTube video about the &lt;strong&gt;SOLD principle&lt;/strong&gt;. That video led me to think that &lt;strong&gt;developing shared components using style inheritance&lt;/strong&gt; could be advantageous for future expansion.&lt;/p&gt;

&lt;p&gt;So I changed all my shared components to use &lt;strong&gt;extension (inheritance)&lt;/strong&gt;. However, I encountered an unexpected bug in the process. Through this bug, I learned the difference between:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Extending (inheriting) components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using branching within a single styled component&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And I'd like to share that experience here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Ways to Handle Variations in Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Using Inheritance (Extend)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a base styled component.&lt;/li&gt;
&lt;li&gt;For each needed variant, extend that base component and apply different styles.&lt;/li&gt;
&lt;li&gt;If you have many variants, adding new ones is straightforward since it simply involves creating more extended components.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Handling Branching within a Single Styled Component
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Pass a value like variant as a prop.&lt;/li&gt;
&lt;li&gt;In a single styled component, use conditionals such as switch or ternary operators to apply different styles.&lt;/li&gt;
&lt;li&gt;This approach handles frequently changing props dynamically and immediately.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Simple Example Code Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Handling Variants with Inheritance
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&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;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ButtonComponent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;variant&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&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;StyledButtonBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
  /* Common styles */
`&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;PrimaryButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;StyledButtonBase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`
  background-color: black;
  color: white;
`&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;DangerButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;StyledButtonBase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`
  background-color: red;
  color: white;
`&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;ButtonComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PrimaryButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;danger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DangerButton&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;• When a new variant is added, you extend StyledButtonBase again (for example, DangerButton) and can easily keep expanding.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Handling Branching within a Single Styled Component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StyledButton&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StyledButton&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&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;StyledButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`
  /* Common styles */
  background-color: &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getBackgroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;
  color: &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBackgroundColor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Theme&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;variant&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="s2"&gt;primary&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;blue&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="s2"&gt;danger&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;red&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gray&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Theme&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;variant&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="s2"&gt;primary&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;white&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="s2"&gt;danger&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;white&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;black&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;*This is not a good example. The button color may change depending on the state after the button component is mounted. Instead of this approach, it is better to use Styled Component inheritance when there are design variations, such as a Background button and a Border button.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Scenario
&lt;/h2&gt;

&lt;p&gt;Let's say we have an InputContainer component that wraps an input. When the input's value changes (onChange), we perform a validation check. If there's an error, we pass variant='error' to change the border color to red.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritance-Based InputContainer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputContainer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;InputContainerProps&lt;/span&gt;&lt;span class="p"&gt;)&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;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;InputContainerComponent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;variant&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&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;BaseInputContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  border: 1px solid black;
`&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;ErrorInputContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BaseInputContainer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`
  border-color: red;
`&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;InputContainerComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BaseInputContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ErrorInputContainer&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;Consider that a re-render takes place. What potential issue could arise here?&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Branching within a Single Styled Component InputContainer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputContainer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;InputContainerProps&lt;/span&gt;&lt;span class="p"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StyledInputContainer&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StyledInputContainer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&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;StyledInputContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`
  border: 1px solid
    &lt;/span&gt;&lt;span class="p"&gt;${({&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;negative&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gray300&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What differences do you see in how the component is re-rendered?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bug I Encountered
&lt;/h2&gt;

&lt;p&gt;I experienced a bug where &lt;strong&gt;the input's focus would disappear&lt;/strong&gt; every time the border color changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Did This Happen?
&lt;/h3&gt;

&lt;p&gt;In the inheritance-based approach, changing the variant &lt;strong&gt;creates what is effectively a new component&lt;/strong&gt; each time. So when variant changes from "default" to "error", React sees the old component unmount and a new one mount. As a result, the original input element is removed, and a new one is created, causing the &lt;strong&gt;loss of focus&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What about the branch inside style approach?&lt;/p&gt;

&lt;p&gt;With props, you're still dealing with the &lt;strong&gt;same component&lt;/strong&gt;. Only the class or inline styles change. Because the same DOM node persists, the focus doesn't get lost when the border color changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Inheritance-Based InputContainer
&lt;/h3&gt;

&lt;p&gt;• When the variant changes, a &lt;strong&gt;different component&lt;/strong&gt; is rendered.&lt;br&gt;
• React may treat it as a completely separate DOM element and re-mount it, depending on the complexity of the structure.&lt;br&gt;
• If you had an input focused inside, it can lose focus due to re-mount.&lt;/p&gt;
&lt;h3&gt;
  
  
  Branch inside style InputContainer
&lt;/h3&gt;

&lt;p&gt;• When the variant changes, the &lt;strong&gt;same component&lt;/strong&gt; remains; only the styling changes.&lt;br&gt;
The focused input remains intact, preserving the focus.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion &amp;amp; Recommendations
&lt;/h2&gt;
&lt;h3&gt;
  
  
  When Should You Use Inheritance?
&lt;/h3&gt;

&lt;p&gt;• The prop that determines branching will &lt;strong&gt;never change after the component mounts&lt;/strong&gt;.&lt;br&gt;
• For example, a Button component with multiple design variations (e.g., Border, Background, etc.).&lt;br&gt;
• Inheritance aligns well with the Open-Closed Principle, allowing new variants to be added without modifying existing code.&lt;/p&gt;
&lt;h3&gt;
  
  
  When Should You Use Props-Based Branching?
&lt;/h3&gt;

&lt;p&gt;• &lt;strong&gt;When there's a lot of user interaction&lt;/strong&gt; and the variant or disabled states change frequently.&lt;br&gt;
• For example, form inputs that can switch to an error state in real-time.&lt;br&gt;
• Because the component doesn't unmount and remount, states like focus are maintained.&lt;/p&gt;
&lt;h4&gt;
  
  
  In the case of Emotion, you can define only the class separately, allowing for extension in accordance with the Open-Closed Principle
&lt;/h4&gt;

&lt;p&gt;By using Emotion’s &lt;code&gt;css&lt;/code&gt; utility as shown below, you can apply the Open-Closed Principle by changing only the class.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;css&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;@emotion/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&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;@emotion/styled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;theme&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;@/styles/theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;InputVariant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;InputContainerProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;className&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="nl"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;InputVariant&lt;/span&gt;&lt;span class="p"&gt;;&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;InputContainer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&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="nx"&gt;InputContainerProps&lt;/span&gt;&lt;span class="p"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StyledInputContainer&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StyledInputContainer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;InputContainer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StyledInputContainerProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InputVariant&lt;/span&gt;&lt;span class="p"&gt;;&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;StyledInputContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StyledInputContainerProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`
  display: flex;
  padding: 11px 18px;
  justify-content: space-between;
  border-radius: 5px;
  background: &lt;/span&gt;&lt;span class="p"&gt;${({&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;white&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="nx"&gt;variant&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;CustomInputContainer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;CustomInputContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultInputContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`
  border: 1px solid &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gray100&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorInputContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`
  border: 1px solid &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;negative&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomInputContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nb"&gt;NonNullable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InputContainerProps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variant&lt;/span&gt;&lt;span class="dl"&gt;"&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;defaultInputContainer&lt;/span&gt;
&lt;span class="o"&gt;&amp;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;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultInputContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;errorInputContainer&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;
  
  
  Final Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For components with frequent real-time UI changes: Handle branching within a single component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For components that do not change dynamically after mounting and need to be extended with multiple types: Use inheritance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If necessary, you can mix both approaches. For example, for a Button component, you can distinguish broad categories (such as design differences like Border and Background) using inheritance, while handling more detailed state changes (such as error or success) via props.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, it's crucial to understand "when the UI changes". I hope this post helps you design shared components with Emotion more effectively!&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Why Zustand State Reset Works Instantly, But React Query Cache Clearing Can Be Tricky</title>
      <dc:creator>Maria Kim</dc:creator>
      <pubDate>Tue, 25 Feb 2025 11:20:33 +0000</pubDate>
      <link>https://dev.to/mariahello/why-zustand-state-reset-works-instantly-but-react-query-cache-clearing-can-be-tricky-1jf</link>
      <guid>https://dev.to/mariahello/why-zustand-state-reset-works-instantly-but-react-query-cache-clearing-can-be-tricky-1jf</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%2Ffgljpl2y4j29z7y2x4ku.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%2Ffgljpl2y4j29z7y2x4ku.png" alt="react img" width="440" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When working with state management and data-fetching libraries in React applications, you might encounter an interesting behavior difference during logout flows or similar global state resets. Specifically, if you use &lt;strong&gt;Zustand&lt;/strong&gt; to manage user state and &lt;strong&gt;React Query&lt;/strong&gt; to manage server-side data, you might notice that resetting Zustand's state works seamlessly, but clearing React Query's cache sometimes requires extra care. This blog will explain &lt;strong&gt;why this happens&lt;/strong&gt; and &lt;strong&gt;how to handle it properly&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Common Logout Example
&lt;/h2&gt;

&lt;p&gt;Imagine you have a logout function like this:&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;onLogout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// logout api&lt;/span&gt;
 &lt;span class="nf"&gt;resetUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Zustand code to clear user state&lt;/span&gt;
 &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// React Query code to clear cache&lt;/span&gt;
 &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Navigate away&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks fine. However, in practice, you might encounter &lt;strong&gt;inconsistent behavior&lt;/strong&gt; with React Query's cache clearing, especially when navigating away (&lt;code&gt;router.push()&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You might end up doing something like this instead:&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;onLogout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="nf"&gt;resetUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Zustand state reset&lt;/span&gt;
 &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// React Query cache clear&lt;/span&gt;
 &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&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;Why does deferring the &lt;code&gt;queryClient.clear()&lt;/code&gt; call with &lt;code&gt;Promise.resolve()&lt;/code&gt; sometimes work better? And why is Zustand's &lt;code&gt;resetUser()&lt;/code&gt; always fine?&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Difference: Zustand vs. React Query
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🐻 Zustand - Simple Synchronous State Update
&lt;/h3&gt;

&lt;p&gt;When you call &lt;code&gt;resetUser()&lt;/code&gt; in Zustand, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mutates the store state synchronously.&lt;/li&gt;
&lt;li&gt;Notifies all subscribed components to re-render if necessary.&lt;/li&gt;
&lt;li&gt;Ignores unmounted components since they are no longer subscribed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🔥 React Query - Cache, Observers, and Side Effects
&lt;/h3&gt;

&lt;p&gt;When you call &lt;code&gt;queryClient.clear()&lt;/code&gt;, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Invalidates and removes query data from the cache.&lt;/li&gt;
&lt;li&gt;Notifies active subscriptions (e.g. components using &lt;code&gt;useQuery()&lt;/code&gt; hooks).&lt;/li&gt;
&lt;li&gt;Handles ongoing network requests, retries, and refetches (if applicable).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key problem is that &lt;strong&gt;if components are in the process of unmounting (e.g., due to &lt;code&gt;router.push()&lt;/code&gt;) while &lt;code&gt;queryClient.clear()&lt;/code&gt; is running&lt;/strong&gt;, you can get into a race condition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components might unsubscribe while React Query is still notifying them.&lt;/li&gt;
&lt;li&gt;Ongoing network requests might still resolve after you clear the cache.&lt;/li&gt;
&lt;li&gt;React Query hooks might still trigger updates for unmounted components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  What is a Race Condition?
&lt;/h4&gt;

&lt;p&gt;A race condition happens when two or more operations happen at the same time, and the final outcome depends on the timing or order of those operations. In this case, clearing the React Query cache and unmounting components due to routing can overlap, leading to unexpected behavior or errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Deferring Works
&lt;/h3&gt;

&lt;p&gt;When you do this:&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You defer the cache clearing to the next microtask. This allows React to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finish unmounting components triggered by &lt;code&gt;router.push()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Unsubscribe any React Query observers tied to those components.&lt;/li&gt;
&lt;li&gt;Safely clear the cache afterward, without interfering with ongoing React lifecycle processes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why Zustand Is Always Safe
&lt;/h3&gt;

&lt;p&gt;Zustand's state update is &lt;strong&gt;synchronous&lt;/strong&gt; and &lt;strong&gt;not lifecycle-sensitive&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you call &lt;code&gt;resetUser()&lt;/code&gt; and a component is still mounted, it re-renders.&lt;/li&gt;
&lt;li&gt;If the component is unmounted, it has already unsubscribed, and nothing happens.&lt;/li&gt;
&lt;li&gt;There's &lt;strong&gt;no async behavior or network lifecycle management&lt;/strong&gt; to interfere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of this simplicity, you can &lt;strong&gt;reset Zustand state at any time&lt;/strong&gt; without worrying about navigation or component lifecycles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary Table
&lt;/h2&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%2Feltwnfzf20wu29k2yrzi.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%2Feltwnfzf20wu29k2yrzi.png" alt="summary" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Understanding &lt;strong&gt;the difference between local synchronous state (Zustand) and asynchronous data-fetching state (React Query)&lt;/strong&gt; is crucial when designing logout flows or global state resets. Zustand's simplicity allows for carefree state updates, while React Query requires &lt;strong&gt;more attention to lifecycle timing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When in doubt, &lt;strong&gt;defer cache clearing&lt;/strong&gt; to ensure &lt;strong&gt;it runs after routing&lt;/strong&gt; transitions complete. This small adjustment can &lt;strong&gt;save you from subtle race conditions and improve your app's stability.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>zustand</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
