<?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: Alejandro</title>
    <description>The latest articles on DEV Community by Alejandro (@alejandrodeveloper).</description>
    <link>https://dev.to/alejandrodeveloper</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4013373%2F0d83b145-0003-4389-9a3b-71517182679f.JPG</url>
      <title>DEV Community: Alejandro</title>
      <link>https://dev.to/alejandrodeveloper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alejandrodeveloper"/>
    <language>en</language>
    <item>
      <title>Part 2: Angular Bundle Size Is Only One Part of Performance</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Mon, 20 Jul 2026 13:20:53 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/part-2-angular-bundle-size-is-only-one-part-of-performance-2dd</link>
      <guid>https://dev.to/alejandrodeveloper/part-2-angular-bundle-size-is-only-one-part-of-performance-2dd</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 2 of the Angular in Production series&lt;/em&gt;&lt;br&gt;
One of the first things people usually check when an Angular application feels slow is the bundle size. That makes sense. If the browser has to download several megabytes of JavaScript before the application can become interactive, the initial experience will probably suffer.&lt;/p&gt;

&lt;p&gt;So developers start looking at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bundle analyzers&lt;/li&gt;
&lt;li&gt;lazy-loaded routes&lt;/li&gt;
&lt;li&gt;tree shaking&lt;/li&gt;
&lt;li&gt;third-party dependencies&lt;/li&gt;
&lt;li&gt;unused code&lt;/li&gt;
&lt;li&gt;build configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all important, but reducing the JavaScript bundle is only one part of improving performance. A smaller bundle can make an application load faster. It does not automatically make the application fast once it is running. That distinction is easy to miss.&lt;/p&gt;


&lt;h3&gt;
  
  
  Loading Performance and Runtime Performance Are Different Problems
&lt;/h3&gt;

&lt;p&gt;Imagine an Angular application with a 3 MB initial JavaScript bundle. The application takes several seconds to become interactive. After optimizing the bundle, the initial JavaScript is reduced to 1 MB.&lt;/p&gt;

&lt;p&gt;The first load improves significantly. But after the application starts, opening a large table still freezes the browser for two seconds. The bundle optimization worked, it just didn't solve the second problem. The application had two different performance bottlenecks. One was related to loading and the other was related to runtime work.&lt;/p&gt;

&lt;p&gt;I try to think about performance in separate stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User opens the application --&amp;gt; Browser downloads resources --&amp;gt; Browser parses and executes JavaScript --&amp;gt; Angular bootstraps --&amp;gt; Application renders --&amp;gt; User interacts with the application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each stage can have a different bottleneck. Optimizing on stage does not necessarily improve the others.&lt;/p&gt;




&lt;h3&gt;
  
  
  A smaller Bundle Still Has to Be Executed
&lt;/h3&gt;

&lt;p&gt;Reducing bundle size is valuable, but the number of bytes downloaded is not the only thing that matters.&lt;/p&gt;

&lt;p&gt;The browser also has to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;download the JavaScript&lt;/li&gt;
&lt;li&gt;parse it&lt;/li&gt;
&lt;li&gt;compile it&lt;/li&gt;
&lt;li&gt;execute it&lt;/li&gt;
&lt;li&gt;create the initial application&lt;/li&gt;
&lt;li&gt;render the result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that two bundles with similar sizes can still behave differently. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application A
1.5 MB JavaScript
Simple initialization
Minimal startup work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application B
1.5 MB JavaScript
Heavy initialization
Multiple API requests
Large amount of synchronous work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They have a similar bundle size. The user experience can still be very different. This is why I try not to use bundle size as a single definition of frontend performance. It is an important metric. It is just not the entire picture.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Initial Bundle Should contain What the User Needs First
&lt;/h3&gt;

&lt;p&gt;One of the most efffetive ways to improve the initial experience is to avoid loading code before it is needed. Consider an application with routes like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dashboard
/orders
/reports
/admin
/settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A user visiting &lt;em&gt;/dashboard&lt;/em&gt; probably doesn't need the entire reporting system and administration panel immediately. Loading all of those features upfront means the browser has to download code for functionality the user may never use.&lt;/p&gt;

&lt;p&gt;Lazy loading gives the application a better boundary:&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;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;loadChildren&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="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;./dashboard/dashboard.routes&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DASHBOARD_ROUTES&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;loadChildren&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="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;./reports/reports.routes&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPORTS_ROUTES&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;Now the reporting code can be loaded when the user actually navigates to that part of the application.&lt;br&gt;
The idea is simple: The initial bundle should contain what is needed to start the application, not necessarily everything the application can do.&lt;br&gt;
This becomes increasingly important as an application grows.&lt;/p&gt;


&lt;h3&gt;
  
  
  Dependencies Can Quietly Become a Performance Problem
&lt;/h3&gt;

&lt;p&gt;One of the easiest ways to increase bundle size is to add another dependency. At the time, the decision often looks completely reasonable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You need a date utility --&amp;gt; you install a library
You need a chart --&amp;gt; you install another library
You need a component --&amp;gt; you install another package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
None of these decisions seems particulary important in isolation. Eventually, however, the application contains a large collection of dependencies. Some of them might be used everywhere. Others might only be used by one feature and others might only be used by one feature. Some might have been added years ago and barely used anymore.&lt;br&gt;
For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as utils from 'large-utility-library';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
may bring a very different amount of code into the application than importing only what is actually needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {formatDate} from 'large-utility-library/date';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
The exact behaviour depends on the package and the build tooling, so I wouldn't assume that every import style automatically produces a problem. But I do think dependencies deserve periodic review. A package is not free just because installing it takes one command. I can affect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bundle size&lt;/li&gt;
&lt;li&gt;build time&lt;/li&gt;
&lt;li&gt;startup time&lt;/li&gt;
&lt;li&gt;maintenance&lt;/li&gt;
&lt;li&gt;security updates&lt;/li&gt;
&lt;li&gt;future migrations&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Third-Party Code Is Still Part of Your Performace Budget
&lt;/h3&gt;

&lt;p&gt;A common mistaje is to think only about the code written inside the application. But the browser doesn't care who wrote the code. Your code and third-party code are still part of the same application. A library might provide useful functionality while also adding significant JavaScript to the initial load.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your application + UI library + Chart library + Editor + Analytics + Date library --&amp;gt; Initial JavaScript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
Sometimes the library is absolutely worth the cost. A complex feature can be much cheaper to maintain by using an established library instead of implementing everything yourself. The question isn't if you can remove every dependency. That would usually be unrealistic. The better question is if this dependency need to be part of the initial experience.&lt;/p&gt;

&lt;p&gt;A rich text editor used only on an admin page probably shouldn't necessarily be downloaded by every user visiting the public application. A charting library used only on one route might be a good candidate for lazy loading. The optimization is not always removing the dependency. Sometimes it is moving it to the point where it is actually needed.&lt;/p&gt;


&lt;h3&gt;
  
  
  Lazy Loading Can Also Be Applied to Features
&lt;/h3&gt;

&lt;p&gt;Route-level lazy loading is usually the first place people look. But the same principle can apply inside a feature. For example, imagine a dashboard with several expensive sections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dashboard
├-- Summary
├-- Activity
├-- Analytics
└-- Export tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
The user may only need the summary immediately. Loading evert chart, export utility and analytics module before the user interacts with them can increase the cost of the initial page. In come cases, loading heavy functionality on demand makes more sense.&lt;br&gt;
The implementation depends on the feature and the Angular version, but the architectural idea is the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load the application --&amp;gt; Load the current feature --&amp;gt; Load expensive functionality --&amp;gt; Only when needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
This is especially useful for features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data visualization&lt;/li&gt;
&lt;li&gt;rich text editors&lt;/li&gt;
&lt;li&gt;PDF generation&lt;/li&gt;
&lt;li&gt;large admin tools&lt;/li&gt;
&lt;li&gt;complex configuration interfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user shouldn't necessarily pay the performance cost of functionality they ever use.&lt;/p&gt;


&lt;h3&gt;
  
  
  But Lazy Loading Is Not Automatically Better
&lt;/h3&gt;

&lt;p&gt;There is also a point where lazy loading can become excessive. If an application splits every small component into a separate chunk, the result may become difficult to reason about. The browser may need to make many additional requests. The application may spend mor time coordinating chunks than it would have spent loading a slightly larger initial bundle.&lt;/p&gt;

&lt;p&gt;This is why I don't think the goal should be to make the initial bundle as small as possible. But the better goal is making the initial bundle appropriate for the first experience. A small bundle that requires many additional requests before the user can actually use the application may not be better than a slightly larger bundle that starts immediately. Performance is about the entire experience, not a single number from a build report.&lt;/p&gt;


&lt;h3&gt;
  
  
  The Next Bottleneck Is Often JavaScript Execution
&lt;/h3&gt;

&lt;p&gt;Even after reducing the amount of JavaScript downloaded, the application can still feel slow. At this point the problem may be the amount of work the browser has to perform after the code arrives. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({ 
    template: `
        &amp;lt;div *ngFor="let product of products"&amp;gt;
            {{ calculatePrice(product) }}
        &amp;lt;/div&amp;gt;
    `
})
export class ProductListComponent {
    calculatePrice(product: Product) {
        return product.price*product.quantity;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
For small list, this may not matter, but for a large list, repeated calculation during rendering can become expensive. The problem here isn't the size of the bundle but the amount of work being performed during runtime. This is where bundle optimization ends and application performance begins.&lt;/p&gt;


&lt;h3&gt;
  
  
  Runtime Performance Starts After the Bundle Has Loaded
&lt;/h3&gt;

&lt;p&gt;When people talk about frontend performance, i'ts easy to focus on everything that happens before the application becomes interactive. But once the JavaScript has been downloaded and Angular has bootstrapped the application, a completely different set of problems can appear.&lt;/p&gt;

&lt;p&gt;This is where the application spends most of its lifetime. The user navigates between routes and tables update, forms change, charts render, dialogs open and close, search result are filtered and if those interactions feel slow, reducing the bundle size won't help anymore. The problem is no longer how much code the browser downloaded. The problem is how much work the application is doing while it runs.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rendering the Same Work Over and Over
&lt;/h3&gt;

&lt;p&gt;One of the most common sources of runtime performance issues is repeated work. Take this simple component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({ 
    selector: 'app-products',
    template: `
        &amp;lt;div *ngFor="let product of products"&amp;gt;
            {{ calculatePrice(product) }}
        &amp;lt;/div&amp;gt;
    `
})
export class ProductsComponent {
    products: Product[] = [];
    calculatePrice(product: Product){
        return product.price*product.quantity;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
There's nothing technically wrong but if the list contains several thousand products and Angular evaluates that function repeatedly during change detection, the cost starts to add up. The calculation itself isn't expensive. Repeating it hundreds or thousands of times is. In cases like this, I usually try to move the work closer to where the data is created instead of where it's rendered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;products = apiProducts.map(product =&amp;gt; ({
    ...product,
    totalPrice: product.price*product.quantity
}));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
Now the template becomes much simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div *ngFor="let product of products"&amp;gt;
    {{ product.totalPrice }}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
Now, the browser spends less time recalculating values that haven't changed.&lt;/p&gt;


&lt;h3&gt;
  
  
  A Fast Route Can Still Feel Slow
&lt;/h3&gt;

&lt;p&gt;Sometimes the route itself loads quickly. The API responds almost instantly and the bundle is already cached. Navigation completes in a fraction of a second. And yet the page still feels sluggish. This usually means the bottleneck isn't the network anymore. It's rendering. For example, rendering a large table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;tr *ngFor="let order of orders"&amp;gt;
    ...
&amp;lt;/tr&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
If &lt;em&gt;orders&lt;/em&gt; contains ten thousand elements, Angular isn't necessarily the problem. The browser now has to create, paint and maintain ten thousand DOM nodes. No framework can completely avoid that cost.&lt;/p&gt;

&lt;p&gt;This is why techniques like pagination or virtual scrolling often have a much larger impact than trying to optimize change detection. The fastest DOM node is the one that doesn't exist.&lt;/p&gt;


&lt;h3&gt;
  
  
  Change Detection Shouldn't Become the Scapegoat
&lt;/h3&gt;

&lt;p&gt;Angular's change detection often gets blamed whenever an application becomes slow. Sometimes that's fair. Most of the time, though, it's simply exposing expensive code that already exists. Consider this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div *ngFor="let user of users"&amp;gt;
    {{ fullName(user) }}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;br&gt;
The problem isn't that Angular is caling &lt;em&gt;fullName()&lt;/em&gt;. The real question is why does rendering this component require recalculating the same value over and over.&lt;br&gt;
Changing the component to &lt;em&gt;OnPush&lt;/em&gt; may reduce how often Angular checks it. It doesn't remove unnecessary work.&lt;/p&gt;

&lt;p&gt;Whenever I profile an application, I try to optimize the work itself before changing the detection strategy. If the application performs less work, every change detection cycle neturally becomes cheaper.&lt;/p&gt;


&lt;h3&gt;
  
  
  Network Performance Is Also Part of Frontend Performance
&lt;/h3&gt;

&lt;p&gt;Another thing that's easy to overlook is duplicated network requests. I've seen applications where several components independently request exactly the same data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.http.get('/api/profile');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then another component that is the same and another and another. Each request may be relatively fast. Together they create unnecessary network traffic, duplicated parsing and additional rendering work.&lt;/p&gt;

&lt;p&gt;Caching or sharing data often provides a larger performance improvement than shaving another fifty kilobytes off the JavaScript bundle. Performance isn't just about the browser. It's also about avoiding unnecessary work across the entire application.&lt;/p&gt;




&lt;h3&gt;
  
  
  My Personal Rule
&lt;/h3&gt;

&lt;p&gt;One idea I come back to repeatedly is that performance works like a budget. Every decision consumes a small part of it. That means another dependency, animation, HTTP request, another large component, subscription and another expensive calcutation. And none of these choices seems particularly important on its own. But after hundreds of similar decisions, the application starts feeling heavier. That's why I rarely ask if the optimization is worth it and i ask instead if the additional work makes worth making every user pay for it. Sometimes the answer is absolutely yes and others it's clear that the work could happen later or not at all.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Bundle size is one of the easiest performance to measure. It's visible in every build, easy to compare between commits and satisfying to reduce but it's only the beginning. Users don't experience performance as a bundle size. That experience depends on much more than the amount of JavaScript downloaded. It depeds on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how much work happens during rendering&lt;/li&gt;
&lt;li&gt;how often expensive calculations are repeated&lt;/li&gt;
&lt;li&gt;how many unnecessary network requests are made&lt;/li&gt;
&lt;li&gt;how much DOM the browser has to manage&lt;/li&gt;
&lt;li&gt;how much code is loaded before it's actually needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optimizing Angular applications isn't about chasing a single number. It's about reducing unnecessary work throughout the application's lifetime.&lt;/p&gt;

&lt;p&gt;Sometimes that means making the bundle smaller, others it means rendering less and others moving calculations. Sometimes it simply means asking whether the application is doing work that nobody benefits form.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Article in This Series
&lt;/h3&gt;

&lt;p&gt;Part 3: The Angular Change Detection Mistakes That Make Large Apps Feel Slow&lt;/p&gt;

&lt;h3&gt;
  
  
  Previous Article in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/part-1-why-angular-applications-get-slower-as-they-grow-4c4c"&gt;Part 1: Why Angular Applications Get Slower as They Grow&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading! If your Angular application has accumulated performance or maintainability problems over time, this is the kind of work I help teams with: debugging existing codebases, improving performance and refactoring incrementally. You have a link to my upWork in my Dev profile.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Part 1: Why Angular Applications Get Slower as They Grow</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Thu, 16 Jul 2026 14:50:26 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/part-1-why-angular-applications-get-slower-as-they-grow-4c4c</link>
      <guid>https://dev.to/alejandrodeveloper/part-1-why-angular-applications-get-slower-as-they-grow-4c4c</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 1 of the &lt;strong&gt;Angular in Production&lt;/strong&gt; series&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most Angular application don't become slow because someone madre one catastrophic mistake. Usually, the application starts normally. When you start, there are a few components, a few routes, some API calls, a couple of forms and everything feels fast enough. But then the application grows and more features are added, more dependencies are installed, more components start sharing data, more business logic moves into services and more API calls happen in the background. Eventually, someone notices that the application doesn't feel as responsive as it used to. The initial load takes longer, navigating between pages feels slower and some screens freeze briefly. A table that used to render instantly now takes noticeable time.&lt;/p&gt;

&lt;p&gt;The first instinc is usually to look for one specific problem. Maybe Angular is running change detection too often or maybe the bundle is too large or there are too many subscription or a component needs &lt;em&gt;OnPush&lt;/em&gt;. Sometimes that's correct but in larger applications, performance problems are usually the result of several small decisions accumulating over time.&lt;/p&gt;




&lt;h3&gt;
  
  
  Performance Problems Usually Accumulate
&lt;/h3&gt;

&lt;p&gt;One of the things I've learned working with frontend applications is that performance problems rarely appear at the same time as the code that caused them. A component might be perfectly acceptable when it renders 20 items. But the same component might become a problem when it renders 10,000. A service might make one API request during a page load. After several features start depending on it, the same service might trigger five requests for the same data. A dependency might add 50KB to the application. &lt;/p&gt;

&lt;p&gt;That doesn't matter much by itself but after several similar decisions, the initial JavaScript bundle becomes signifantly larger. The code didn't necessarily become bad overnight. The application simply grew beyond the assumptions that were made when the original code was written. This is why optimizing a large Angular application is often less about finding a single "magic fix" and more about understanding where the application is spending its time.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Application Has More Than One Performance Problem
&lt;/h3&gt;

&lt;p&gt;When someone says that the Angular app is slow, that can mean several completely different things. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the first page takes too long to load&lt;/li&gt;
&lt;li&gt;navigation feels slow&lt;/li&gt;
&lt;li&gt;typing in a form is laggy&lt;/li&gt;
&lt;li&gt;a table takes several seconds to render&lt;/li&gt;
&lt;li&gt;API requests are duplicated&lt;/li&gt;
&lt;li&gt;the browser uses too much memory&lt;/li&gt;
&lt;li&gt;the application freezes during a particular interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems don't necessarily have the same cause. A slow initial load is usually a different problem from a slow table, and that is different from a memory leak and different from an API request that takes five seconds. I know this sounds obvious, but it's easy to forget when performance work starts with assumptions instead of measurements.&lt;/p&gt;




&lt;h3&gt;
  
  
  The First Thing I Check Is Usually Not Angular
&lt;/h3&gt;

&lt;p&gt;When an application feels slow, my first instinct nowadays is not to immediately change the Angular code. I want to know where the time is going first. &lt;/p&gt;

&lt;p&gt;This is why I don't like generic performance advice such as "Just use OnPush" or "Add lazy loading" or "Use signals". Those can all be useful but applying them without knowing the bottleneck is mostly guesswork.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Large Bundle Is Not Always a Runtime Problem
&lt;/h3&gt;

&lt;p&gt;One of the easiest performance problems to understand is the initial JavaScript bundle.&lt;br&gt;
Imagine an application that downloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main.js           3.2 MB
vendor.js         1.8 MB
styles.css        400 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user needs to download, parse and execute all of that before the application becomes fully usable. That obviously create a bad initial experience. But reducing the bundle size won't necessarily fix a slow interaction after the application has loaded.&lt;br&gt;
For example, this component might still be slow:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;`
        &amp;lt;div *ngFor="let order of orders"&amp;gt;
            {{ calculateTotal(order) }}
        &amp;lt;/div&amp;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;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersComponent&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nf"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Order&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;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&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;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="mi"&gt;0&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;Even if the application has a tiny initial bundle, repeatedly doing expensive work during rendering can still make the interface feel slow. This is one of the reasons I try to separate two questions: how quickly can the application start and how efficiently does it behave once it is running. they are related but they are not the same problem.&lt;/p&gt;




&lt;h3&gt;
  
  
  Components Often Become the Place Where Everything Meets
&lt;/h3&gt;

&lt;p&gt;Another common pattern appears as an application grows. A component starts small.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Order&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then more features get added.&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="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;classe&lt;/span&gt; &lt;span class="nx"&gt;OrdersComponent&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Order&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="nx"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;showModal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;loadOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nf"&gt;applyFilters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nf"&gt;exportOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nf"&gt;deleteOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nf"&gt;calculateTotals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nf"&gt;updatePagination&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;Eventually the component becomes responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;loading data&lt;/li&gt;
&lt;li&gt;transforming API responses&lt;/li&gt;
&lt;li&gt;managing filters&lt;/li&gt;
&lt;li&gt;handling forms&lt;/li&gt;
&lt;li&gt;controlling modals&lt;/li&gt;
&lt;li&gt;calculating business logic&lt;/li&gt;
&lt;li&gt;managing pagination&lt;/li&gt;
&lt;li&gt;displaying the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, performance and maintainability problems often start appearing together. The component has too many responsibilities. A change in one area can affect anther and it becomes harder to understand what causes a render or which operation its expensive. And it becomes harder to optimize anything without worrying about breaking something else. I don't think the solution is to split every component into the smallest possible pieces that often creates a different kind of complexity.&lt;/p&gt;

&lt;p&gt;The more question to ask yourself is if this component still have a clear responsibility and if the answer is no, performance work becomes much harder because the boundaries of the application are already unclear.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Same Data Is Often Loaded More Than Once
&lt;/h3&gt;

&lt;p&gt;One of the most common problems I see in growing applications is duplicated work.&lt;br&gt;
For example:&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="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&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;More than one component does this same thing and each component is independently asking for the same information. The application may end up making several requests for data that hasn't changed. This is not necessarily a problem when there are only two components but as the application grows, the number of requests can increase without anyone explicitly deciding that it should.&lt;br&gt;
A shared data layer can help:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;user$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user')
        .pipe(
           shareReplay({bufferSize: 1, refCount: true})
        );
    getCurrentUser(){
        return this.user$;
    }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now multiple consumers can share the same request and cached result. The exact solution depends on the application. Sometimes a simple service is enough, others a query library is more appropiate and others the data should be loaded at the route level.&lt;/p&gt;

&lt;p&gt;The important part is recognizing that every component independently loading the same data is often a sign that the application has no clear ownership of that data.&lt;/p&gt;




&lt;h3&gt;
  
  
  Performance Problems Are Often Architeture Problems
&lt;/h3&gt;

&lt;p&gt;This is probably the main reason I don't like treating Angular performance as a collection of isolated tricks.&lt;br&gt;
A slow application can be caused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;too much JavaScript&lt;/li&gt;
&lt;li&gt;expensive rendering&lt;/li&gt;
&lt;li&gt;unnecessary change detection&lt;/li&gt;
&lt;li&gt;duplicated API calls&lt;/li&gt;
&lt;li&gt;large components&lt;/li&gt;
&lt;li&gt;unbounded lists&lt;/li&gt;
&lt;li&gt;memory leaks&lt;/li&gt;
&lt;li&gt;unnecessary state synchronization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those problems often have something in common. The application is doing work in places where it doesn't need to. Sometimes that means a component is recalculating something. Sometimes it means the same data is being fetched multiple times. Sometimes ut neabs the browser is loading code for a feature the user hasn't opened yet and others it means a subscription remains active long after the component that created it has disappeared. The solution is rarely to optimize everything. Usually, the biggest improvement comes from finding the work that matters most and removing or delaying it.&lt;/p&gt;


&lt;h3&gt;
  
  
  Start With the Biggest Bottleneck
&lt;/h3&gt;

&lt;p&gt;When i start investigating a slow Angular application, I try not to optimize everything at once. That usually creates a lot of work without necessarily improving the user experience. Instead, I try to answer a simpler question: what is the application spending msot of its time doing?&lt;/p&gt;

&lt;p&gt;For an initial load, that might be downloading and executing too much JavaScript. For a slow screen, it might be rendering thousands of DOM nodes. For a lagy interaction, it might be expensive work happening repeatedly during change detection. For a page that becomes slower over time, it might be a memory leak. The solution depends on the bottleneck.&lt;/p&gt;


&lt;h3&gt;
  
  
  Initial Load: Ship Less Code
&lt;/h3&gt;

&lt;p&gt;If the problem is the initial bundle, the first things I usually look at are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lazy-loaded routes&lt;/li&gt;
&lt;li&gt;large third-party dependencies&lt;/li&gt;
&lt;li&gt;code that is loaded before it is needed&lt;/li&gt;
&lt;li&gt;duplicated libraries&lt;/li&gt;
&lt;li&gt;unnecessarily large assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a feature that is only used by a small percentage of users probably shouldn't be part of the initial application bundle.&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;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;loadChildren&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="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;./reports/reports.routes&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPORTS_ROUTES&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 user doesn't need to download the reporting feature before they have even opened it. The important point is that bundle optimization is only one part of the larger performance picture.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rendering: Don't Make the Browser Do Unnecessary Work
&lt;/h3&gt;

&lt;p&gt;Large collections are another common source of problems. Rendering thousands of elements at once can be expensive regardless of how well the rest of the application is structured.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let item of items"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{item.bane}}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;em&gt;items&lt;/em&gt; contains a few dozen elements, this is usually fine. If it contains thousands, the browser has to create and manage thousands of DOM nodes. At that point, pagination or virtual scrolling may be a better solution than trying to optimize the loop itself. The goal isn't always to make Angular render more efficiently. Sometimes the best optimization is simply not rendering things that the user cannot see.&lt;/p&gt;




&lt;h3&gt;
  
  
  Change Detection: Avoid Repeating Expensive Work
&lt;/h3&gt;

&lt;p&gt;Another area I pay attention to is what happens during change detection. Code like this can become expensive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    {{calculateTotal(order)}}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;em&gt;calculateTotal&lt;/em&gt; performs non-trivial work and is called repeatedly, the application may spend a surprising amount of time recalculating the same value. Moving the calculation to a more appropriate place can help:&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="nx"&gt;orders&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&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="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&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;Or, depending on the situation, using a more appropriate change detection strategy can reduce unnecessary work. But again, I wouldn't start by changing every component to &lt;em&gt;OnPush&lt;/em&gt; without understanding the data flow. A performance optimization should solve a measured problem, not just follow a checklist.&lt;/p&gt;




&lt;h3&gt;
  
  
  Memory Problems Are Usually Les Obvious
&lt;/h3&gt;

&lt;p&gt;Some performance probloems don't appear immediately. An application can feel perfectly fine when the user first opens it but after navigating through the application for several minutes, however, memory usage can continue increasing. One possible cause is a subscription that remains active after its component has been destroyed. Modern Angular provides tools that make cleanup easier:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;takeUntilDestroyed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;fronm&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core/rxjs-interop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events$&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntilDestroyed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// handle event&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 specific solution depends on the situation, but the general problem is the same: A component should not continue doing work after it no longer exists. This is one of the reasons performance testing should include more than the initial page load.&lt;/p&gt;




&lt;h3&gt;
  
  
  Measure Before Changing the Architecture
&lt;/h3&gt;

&lt;p&gt;The larger an Angular application becomes, the more tempting it is to start making large architectural changes.&lt;/p&gt;

&lt;p&gt;Rewrite the state management. Replace the component structure. Migrate everything to a new pattern. Rewrite the API layer. Sometimes those changes are necessary but they can also create a lot of risk without addresing the actual bottleneck. &lt;/p&gt;

&lt;p&gt;A more useful process is usually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Measure --&amp;gt; Find the biggest bottleneck --&amp;gt; Change one thing --&amp;gt; Measure again --&amp;gt; Keep or revert the change
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might mean checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bundle analysis&lt;/li&gt;
&lt;li&gt;browser performace profiles&lt;/li&gt;
&lt;li&gt;network requests&lt;/li&gt;
&lt;li&gt;memory usage&lt;/li&gt;
&lt;li&gt;rendering behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is having evidence before and after the change.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Angular applications rarely become slow because of one bad decision. They become slow because the application keeps growing thile the assumptions behind the original architecture stay the same.&lt;/p&gt;

&lt;p&gt;A component that was perfectly reasonable at the beggining may become too expensive once it renders thousands of items. A service that made one API call may eventually be used by ten different components. A dependency that seemed insignificant may become part of a large initial bundle. A subscription that seemed harmless may remain alive long after its component has disappeared. &lt;/p&gt;

&lt;p&gt;This is why I don't think performance optimization should start with a list of Angular features to enable. The first step is understanding what the application is actually doing. Then the optimization becomes much more specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;load less code&lt;/li&gt;
&lt;li&gt;render less&lt;/li&gt;
&lt;li&gt;avoid repeating expensive work&lt;/li&gt;
&lt;li&gt;eliminate duplicated requests&lt;/li&gt;
&lt;li&gt;clean up resources&lt;/li&gt;
&lt;li&gt;improve the boundaries between parts of the application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest improvements often come from removing unneessary work rather than making the existing work slightly faster.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Article in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/part-2-angular-bundle-size-is-only-one-part-of-performance-2dd"&gt;Part 2: Angular Bundle Size Is Only One Part of Performance&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading! If your Angular application has accumulated performance or maintainability problems over time, this is the kind of work I help teams with: debugging existing codebases, improving performance and refactoring incrementally. You have a link to my upWork in my Dev profile.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Part 5: Stop Using Effects for State Resets</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Thu, 16 Jul 2026 11:42:31 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/part-5-stop-using-effects-for-state-resets-4ado</link>
      <guid>https://dev.to/alejandrodeveloper/part-5-stop-using-effects-for-state-resets-4ado</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 5 and last of the &lt;strong&gt;Modern React Patterns&lt;/strong&gt; series&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Throughout this series, we've looked at several situations where useEffect is often used to coordinate state that didn't actually need coordinating. Derived values were recalculated inside Effects instead of during rendering. Server data was fetched inside Effects instead of being managed by a data-fetching layer. Props were copied into local state and then synchronized manually. User actions were converted into state changes just to trigger an Effect. The patern in this article is slightly different. This time, the state itself may be perfectly valid. The problem is that we're trying to reset it manually when the component's context changes. That's where I often see code like this:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setSelectedItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setFormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialData&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="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of these can be correct in some situations. But quite often, the component doesn't need to reset its state. It needs to be treated as a new component.&lt;/p&gt;




&lt;h3&gt;
  
  
  The State Belongs to the Component Instance
&lt;/h3&gt;

&lt;p&gt;Let's start with a simple example. Imagine a chat application. The same message composer is used for different conversations:&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;function&lt;/span&gt; &lt;span class="nf"&gt;ChatPage&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;conversationId&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;MessageComposer&lt;/span&gt;
            &lt;span class="na"&gt;conversationId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conversationId&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;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the composer, we have local state:&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;function&lt;/span&gt; &lt;span class="nf"&gt;MessageComposer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;conversationId&lt;/span&gt;&lt;span class="p"&gt;}){&lt;/span&gt;
    &lt;span class="kd"&gt;const&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="nx"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&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;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 user types a message and then they switch to another conversation. Next, the new conversation should have a new empty composer.&lt;br&gt;
A common solution is to reset the state when the ID changes:&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;function&lt;/span&gt; &lt;span class="nf"&gt;MessageComposer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;conversationId&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="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="nx"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;conversationId&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="nt"&gt;textarea&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&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;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;Again, it works, but the component is still the same React instance. We're keeping it alive and manually trying to make it behave like a new one. There's often a simpler way.&lt;/p&gt;




&lt;h3&gt;
  
  
  Use &lt;em&gt;key&lt;/em&gt; When the Component Represents a New Entity
&lt;/h3&gt;

&lt;p&gt;Instead of resseting the component internally, we can tell React that the identity has changed.&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;function&lt;/span&gt; &lt;span class="nf"&gt;ChatPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;conversationId&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;MessageComposer&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conversationId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;conversationId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conversationId&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;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when &lt;em&gt;conversationId&lt;/em&gt; changes, React sees a different key. The previous &lt;em&gt;MessageComposer&lt;/em&gt; is removed and a new one is created. Its state start from the initial value again.&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;function&lt;/span&gt; &lt;span class="nf"&gt;MessageComposer&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;conversationId&lt;/span&gt;&lt;span class="p"&gt;}){&lt;/span&gt;
    &lt;span class="kd"&gt;const&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="nx"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="si"&gt;}&lt;/span&gt;}
        /&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no Effect, no manual reset or synchronization logic. The component simply starts with a new state because it represents a new entity. This is one of those React features that I completely underestimated when I was learning the framework. I used to think of &lt;em&gt;key&lt;/em&gt; mainly as something required when rendering lists. But keys are also how React determines thew identity of components. That makes them useful far beyond arrays.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Key Is About Identity, Not Just Lists
&lt;/h3&gt;

&lt;p&gt;When React renders a component, it doesn't only look at the component type. It also considers its position in the tree and its key. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Chat&lt;/span&gt; &lt;span class="na"&gt;conversationId=&lt;/span&gt;&lt;span class="s"&gt;"one"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Chat&lt;/span&gt; &lt;span class="na"&gt;conversationId=&lt;/span&gt;&lt;span class="s"&gt;"two"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;are still the same component type in the same position.&lt;br&gt;
React can preserve its state. But:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Chat&lt;/span&gt;
    &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"one"&lt;/span&gt;
    &lt;span class="na"&gt;conversationId=&lt;/span&gt;&lt;span class="s"&gt;"one"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Followed by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Chat&lt;/span&gt;
    &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"two"&lt;/span&gt;
    &lt;span class="na"&gt;conversationId=&lt;/span&gt;&lt;span class="s"&gt;"two"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;represents a different identity. React can now discard the previous state and create a fresh instance. That's exactly what we want when the state belongs to a specific entity. The conversation has changed and the form should be new.&lt;/p&gt;




&lt;h3&gt;
  
  
  Forms Are a Good Example
&lt;/h3&gt;

&lt;p&gt;This becomes especially useful with forms.&lt;br&gt;
Imagine an edit page:&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserPage&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Userform&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&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;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The form has local state:&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserForm&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;email&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;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="si"&gt;}&lt;/span&gt;}
            /&amp;gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a reasonable design; the form owns a draft and the draft is allowed to differ form the server data. That's exactly the distinction we discussed in the previous article. The problem appears when we navigate from one user to another.&lt;br&gt;
Without a key:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserForm&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React may preserve the existing state. The component is still in the same position in the tree. So the form that was editing User A may continue to contain User A's local draft even though the &lt;em&gt;user&lt;/em&gt; prop now represents User B.&lt;br&gt;
A common fix is:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setName&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setEmail&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;email&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now we're back to synchronizing prop into state and the problems start appearing again. A user might be editing a form when a background refetch happens. The action goes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The server object changes --&amp;gt; the effect runs --&amp;gt; The local draft gets overwritten
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reset logic has now become part of the component's behaviour. Instead, when the form represents a completely different user, I usually prefer:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserForm&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the state naturally belongs to the user being edited and then the user changes, the form is recreated.&lt;/p&gt;




&lt;h3&gt;
  
  
  This Is Different Form Resetting a Form After Saving
&lt;/h3&gt;

&lt;p&gt;It's important not to overapply this pattern. There is a difference between "the user changed, so this is a new form" and "the user submitted the form, so I want to clear it".&lt;br&gt;
The first is an identity change and a &lt;em&gt;key&lt;/em&gt; may be a good solution and the second one is an event ans that usually belongs i the submit handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&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;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&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;The fact that both situations involve "resetting state" doesn't mean they should be solved the same way.&lt;br&gt;
The important question is what caused the reset.&lt;/p&gt;


&lt;h3&gt;
  
  
  Resseting State Can Be a Sign of a Component Boundary Problem
&lt;/h3&gt;

&lt;p&gt;Sometimes the problem isn't that the state needs to be reset, the problem is that the component owns too much state.&lt;br&gt;
For 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;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}){&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedColor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedSize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuantity&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setSelectedColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setSelectedSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setQuantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="nx"&gt;productId&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;// ...&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 works, but the Effect is responsible for manually resetting every piece of local state whenever the product changes. As the component grows, the reset list grows with it. A new piece of state gets added. Someone forgets to add it to the Effect and now the new product open with state from the previous product. This is the kind of code that often works perfectly until the component becomes large enough. At that point, the reset Effect becomes a maintenance problem.&lt;/p&gt;




&lt;h3&gt;
  
  
  When &lt;em&gt;key&lt;/em&gt; Is the Right Tool
&lt;/h3&gt;

&lt;p&gt;The most useful I've found to think about this is simple: If the component represents a different entity, changing the key is often the cleanest way to reset its local state. For 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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductEditor&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;em&gt;productId&lt;/em&gt; changes, the editor is no longer editing the same thing. A new component instance makes sense.&lt;br&gt;
The same idea works for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;switching between users&lt;/li&gt;
&lt;li&gt;changing conversations&lt;/li&gt;
&lt;li&gt;navigating between documents&lt;/li&gt;
&lt;li&gt;opening a form for a different record&lt;/li&gt;
&lt;li&gt;changing the current step of an independent workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all of these cases, the state belongs to the entity being displayed. A new entity should usually get a new state-&lt;/p&gt;


&lt;h3&gt;
  
  
  When You Should Not Use &lt;em&gt;key&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;This doesn't mean that &lt;em&gt;key&lt;/em&gt; should become a replacement for every reset Effect. Sometimes the component is still the same component and the state be preserved.&lt;br&gt;
For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Tabs&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Profile&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Settings&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Tabs&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user switches between tabs, you might intentionally want each tab to preserve its state. In that case, destroying and recreating the component would be the wrong behavior. The same applies when only part of the state needs to change. If the user selects a new filter but you want to preserve their sort order, pagination or other local preferences, remounting the entire component may reset too much. This is why I don't think of &lt;em&gt;key&lt;/em&gt; as a generic "reset button". It is primarily about identity.&lt;/p&gt;




&lt;h3&gt;
  
  
  My Personal Rule
&lt;/h3&gt;

&lt;p&gt;The question it's not if you can use a key to reset this component, i'ts if this represent a different instance of the same thing. And if the answers is yes, &lt;em&gt;key&lt;/em&gt; is often a good fit.&lt;/p&gt;




&lt;h5&gt;
  
  
  The Pattern I Try to Avoid
&lt;/h5&gt;

&lt;p&gt;The pattern I now question is this:&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;function&lt;/span&gt; &lt;span class="nf"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}){&lt;/span&gt;
    &lt;span class="kd"&gt;const&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;setState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before keeping the Effect, I ask whether the component should simple be recreated:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes the answer is yes and sometimes it isn't. The important part is understanding why the state is being reset instead of automatically reaching for and Effect.&lt;/p&gt;




&lt;p&gt;In general terms: use state for information that should persist within a component instance and use &lt;em&gt;key&lt;/em&gt; when the component should become a new instance.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;After working on larger React applications, I've become much more suspicious of Effects whose only purpose is to reset local state. Not because they are always wrong but because they often indicate that React's component identity isn't matching the way we think about the data. If a component moves from editing User A to editing User B, those are often two different component instances from a state perspective.&lt;/p&gt;

&lt;p&gt;If a form changes from Product A to Product B, its draft probably shouldn't be manually synchronized with an Effect. An if a component is still representing the same entity, then its state probably shouldn't be reset just because some unrelated prop changed. And that leads us to the general rule I said before.&lt;/p&gt;




&lt;h3&gt;
  
  
  Finally
&lt;/h3&gt;

&lt;p&gt;Across these five artiles, we've looked at some of the most common situations where &lt;em&gt;useEffect&lt;/em&gt; is used as a general-purpose tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;derived values that can be calculated during render&lt;/li&gt;
&lt;li&gt;data fetching that belongs in a data-fetching layer&lt;/li&gt;
&lt;li&gt;props that don't need to be synchronized into state&lt;/li&gt;
&lt;li&gt;user actins that belong in event handlers&lt;/li&gt;
&lt;li&gt;state resets that can often be handled through component identity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread isn't that &lt;em&gt;useEffect&lt;/em&gt; is bad. It's that Effects should have a clear reason to exist.&lt;/p&gt;




&lt;h3&gt;
  
  
  Previous Articles in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f"&gt;Part 1: Why I Rarely Use useEffect Anymore (and what I use instead)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg"&gt;Part 2: Stop Fetching Data Inside useEffect (what modern React apps do instead)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-3-stop-syncing-props-into-state-you-probably-dont-need-that-useeffect-2330"&gt;Part 3: Stop Syncing Props Into State&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/you-probably-dont-need-that-useeffect-event-handlers-are-usually-the-better-place-for-side-effect-4phf"&gt;Part 4: Event handlers are usually the better place for side effect&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading!! If you're looking for help with an existing project or need someone to solve a tricky frontend/backend issue, you can also find my freelance profiles through my Dev.to profile.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Part 4: Event handlers are usually the better place for side effect</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Thu, 16 Jul 2026 08:53:31 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/you-probably-dont-need-that-useeffect-event-handlers-are-usually-the-better-place-for-side-effect-4phf</link>
      <guid>https://dev.to/alejandrodeveloper/you-probably-dont-need-that-useeffect-event-handlers-are-usually-the-better-place-for-side-effect-4phf</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 4 of the &lt;strong&gt;Modern React Patterns&lt;/strong&gt; series&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous articles we've been removing useEffects that existed only because React was being asked to synchronize things it already knows how to synchronize. Firstg we looked at derive state, then data fetching and then synchronizing props into state. This time the problem is slightly different. The useEffect isn't synchronizing data anymore. Instead, it's being used to react to something the user just did. Over the years I've noticed this is another pattern that slowly disappears as React developers gain experience. Not because useEffect is wrong. But because event handlers are usually a much more natural place for that logic.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Pattern That Looks Perfectly Reasonable
&lt;/h3&gt;

&lt;p&gt;Imagine a form with a Save button.&lt;br&gt;
One implementation might look like this:&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserForm&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldSave&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldSave&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;shouldSave&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="nx"&gt;save&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;setShouldSave&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="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldSave&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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="nf"&gt;setShouldSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;Save&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&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;There's nothing obviously wrong here. Clicking the button changes some state. The Effect notices that change. The save operation runs. It works. I've seeen this pattern in production more times than I can count. In fact, I used to write code like this myself because it felt like I was "keeping side effects inside useEffect", which sounded like good React practice. The problem is that this Effect isn't synchronizing with an external system. It's simply reacting to an event that we already know happened.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Event Already Happened
&lt;/h3&gt;

&lt;p&gt;When someone clicks the button, React already gives us the perfect place to respond. The click handler. Instead of storing a flag that says "someone clicked Save", we can simply save immediately.&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserForm&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;handleSave&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;saveUser&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSave&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;Save&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&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;The component suddenly becomes easier to read. There isn't any intermediate state or another render whose only purpose is triggering an Effect. The action happens exactly where the event occurs.&lt;br&gt;
Nowadays, whenever I review code and find boolean flags like &lt;em&gt;shouldSave&lt;/em&gt;, &lt;em&gt;shouldDelete&lt;/em&gt; or &lt;em&gt;shouldSubmit&lt;/em&gt;, it's usually one of the first things I look at. very often they're only there to wake up an Effect.&lt;/p&gt;


&lt;h3&gt;
  
  
  Boolean Flags Usually Hide Event Logic
&lt;/h3&gt;

&lt;p&gt;After seeing this pattern enough times, I started noticing the same variable names appearing over and over again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldFetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldFetch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldDelete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldDelete&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldSubmit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldExport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldExport&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of these aren't really pieces of state. They're event pretending to be state. That's an important distinction. State describeshow the UI looks right now and events describe something that happened. A button click isn't application state, it's simply an interaction. When we convert events into state, we usually end up writing an Effect whose only responsibility is translating that state back into the original action.&lt;br&gt;
In other words, this is the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User clicks --&amp;gt; State changes --&amp;gt; Component renders again --&amp;gt; Effect runs --&amp;gt; Actual work starts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a surprisingly long journey for something that could have happened directly inside the click handler.&lt;/p&gt;




&lt;h3&gt;
  
  
  Effects Are About Synchronization
&lt;/h3&gt;

&lt;p&gt;One idea that completely changed the way I use useEffect came directly from the React documentation. Effects exist to synchronize your component with something outside React. That could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;opening a WebSocket&lt;/li&gt;
&lt;li&gt;subscribing to browser events&lt;/li&gt;
&lt;li&gt;integrating a third-party library&lt;/li&gt;
&lt;li&gt;controlling a video player&lt;/li&gt;
&lt;li&gt;updating the document title&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are external systems, a button click, saving a form or deleting a record isn't. Those actions originate inside React and there's no synchronization involved. Once I started thinking about Effects this way, I noticed I was deleting far more of them than adding new ones.&lt;/p&gt;




&lt;h3&gt;
  
  
  Extra State Usually Means Extra Complexity
&lt;/h3&gt;

&lt;p&gt;Let's imagine the save operation becomes slightly more complicated. We want to show a loading spinner. With the previous approach, we now have several moving parts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldSave&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldSave&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;shouldSave&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;saveUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&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="nf"&gt;setShouldSave&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="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;save&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="nx"&gt;shouldSave&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing here is technically incorrect but notice how much machinery appeared around what was originally just "save when the user clicks". Compare it with keeping everything inside the event handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&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;saveUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&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="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;Personally, I find this version much easier to follow. Everything related to saving lives in one place. The button starts the action, the handler performs the action and the loading state belongs to the action. There aren't multiple renders whose only purpose is coordinating when work should begin.&lt;/p&gt;




&lt;h3&gt;
  
  
  React Doesn't Need a Trigger Variable
&lt;/h3&gt;

&lt;p&gt;One thing I notice quite often is that developers coming from other frameworks tend to think they need a variable that "activates" some behavior. React usually doesn't. If the user clicks something, React already tells us exactly where that happened. If a request should start after submitting a form, React already tells us which function handles the submit.&lt;/p&gt;

&lt;p&gt;Adding another state variable often doesn't make the logic clearer. It simply delays the real work until after another render. That doesn't sound like much, but once components grow, these little patterns accumulate surprisingly quickly. One Effect becomes three. Then five and eventually the component spends more time coordinating itself than implementing the actual business logic.&lt;/p&gt;




&lt;h3&gt;
  
  
  When an Effect Is Actually the Right Choice
&lt;/h3&gt;

&lt;p&gt;The point of this article isn't that every side effect should move into an event handler. That would be just another rule to follow without understanding the reason behind it. There are plenty of situations where an Effect is exactly the right tool.&lt;/p&gt;

&lt;p&gt;The difference is what caused the work to happen. If the work started because the user clicked a button, the event handler is usually the right place. And if the work needs to happen because something outside the component changed, an Effect may be the right solution.&lt;/p&gt;




&lt;h3&gt;
  
  
  External Changes Are Different
&lt;/h3&gt;

&lt;p&gt;Imagine a component that connects to a WebSocket.&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&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 a good use of useEffect. The WebSocket is an external system. React needs to synchronize with it. When url changes, the connection needs to be recreated. When the component unmounts, the connection needs to be cleaned up. The Effect describes that lifecycle clearly. The same idea applies to browser event listeners:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleResize&lt;/span&gt; &lt;span class="o"&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="nf"&gt;setWindowWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleResize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleResize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component is synchronizing with something outside React. That's what Effects are good at.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Difference Is the Cause
&lt;/h3&gt;

&lt;p&gt;Compare these two examples.&lt;/p&gt;

&lt;h5&gt;
  
  
  User clicks a button
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSave&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Save
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The event handler should usually perform the save.&lt;/p&gt;

&lt;h5&gt;
  
  
  A WebSocket sends a message
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handleMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Effect is appropriate because the event comes from an external system. The code may look similar because both situations involve something happening. But the source of the event is different and that's the distinction I find most useful.&lt;/p&gt;




&lt;h3&gt;
  
  
  My Personal Rule
&lt;/h3&gt;

&lt;p&gt;A useful rule I now try follow is that if something happened, handle the event. If something is now true, represent it as state.&lt;br&gt;
For example:&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="c1"&gt;// Event&lt;/span&gt;
&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSave&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is different from:&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="c1"&gt;// State&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSaving&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSaving&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The click happened once. &lt;em&gt;isSaving&lt;/em&gt; describes the current state of the application. Those shouldn't be trated as the same thing. When an event becomes a boolean flag just tot trigger an Effect, the code is usually becoming more complicated than necessary.&lt;/p&gt;




&lt;p&gt;When I find myself writing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldDoSomething&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShouldDoSomething&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState &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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldDoSomething&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;shouldDoSomething&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I stop and ask mysellf what caused this work to happen.&lt;br&gt;
If the answer is that the user clicked a button, then the code probably belongs here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&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="nf"&gt;doSomething&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;If the answer is a WebSocket message arrived, the url changed, a third-party library changed or the browser fired an event, then an Effect might be exactly what the component needs. This small distinction has made a big difference in the way I structure React components.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I don't think useEffect is difficult because the API itself is complicated. The difficult part is deciding whether the code actually belongs there.&lt;/p&gt;

&lt;p&gt;For a long time, I treated Effects as a general-purpose place for anything that wasn't rendering UI. That usually led to state flags, dependency arrays, extra renders and components that were difficult to follow.&lt;br&gt;
Now I try to start from the cause instead. If the user did something, I usually handle it in an event handler and if an external system changed, I consider an Effect. That doesn't eliminate every Effect form a React application. It just means that the ones that remain usually have a clearer reason for existing.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Article in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/part-5-stop-using-effects-for-state-resets-4ado"&gt;Part 5: Stop Using Effects for State Resets&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Previous Articles in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f"&gt;Part 1: Why I Rarely Use useEffect Anymore (and what I use instead)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg"&gt;Part 2: Stop Fetching Data Inside useEffect (what modern React apps do instead)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-3-stop-syncing-props-into-state-you-probably-dont-need-that-useeffect-2330"&gt;Part 3: Stop Syncing Props Into State&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading!! If you're looking for help with an existing project or need someone to solve a tricky frontend/backend issue, you can also find my freelance profiles through my Dev.to profile.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>react</category>
      <category>coding</category>
    </item>
    <item>
      <title>Part 3: Stop Syncing Props Into State</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Wed, 15 Jul 2026 12:00:53 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/part-3-stop-syncing-props-into-state-you-probably-dont-need-that-useeffect-2330</link>
      <guid>https://dev.to/alejandrodeveloper/part-3-stop-syncing-props-into-state-you-probably-dont-need-that-useeffect-2330</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 3 of the &lt;strong&gt;Modern React Patterns&lt;/strong&gt; series&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous article (&lt;a href="https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg"&gt;Part 2: Stop Fetching Data Inside useEffect (what modern React apps do instead)&lt;/a&gt;) we talked about one of the biggest reasons why React applications end up full of unnecessary Effects: fetching server data inside useEffect.&lt;br&gt;
This time I want to cover another pattern that I still find suprisingly often during code reviews, even in mature codebases. Synchronizing props into local state, at first, it doesn't even look like a mistake. Actually, it feels like the obvious thing to do lije a parent passes some data, the child stores it in its own state and whenever the parent changes, the child updates its copy. Except that, in most cases, React never needed that second copy to exist.&lt;/p&gt;


&lt;h3&gt;
  
  
  The Pattern Everyone Writes at Some Point
&lt;/h3&gt;

&lt;p&gt;If you've been writing React for a while, you've probably written something like this:&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setName&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;name&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="nx"&gt;user&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="nt"&gt;input&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;setname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;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;I've written code like this many times. I've also reviewed dozens of components doing exactly the same thing. The interesting part is that it usually works; nothing crashes, there are no console warnings, the UI behaves correctly during development, and that's why this pattern survives for so long. The problem don't usually appear until the component grows.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why It Feels Like the Right Solution
&lt;/h3&gt;

&lt;p&gt;When you're new to React, this pattern makes perfect sense. You receive some data, you keep it in state and when the prop changes, you synchronize it. Coming from other UI frameworks, this mental model feels completely natural. The problem is that React already re-renders your component every time its props change. That mean the prop is alrady synchronized. By copying it into state, you've created two values that are supposed to represent exactly the same thing. Now React has to keep both in sync. Not because React needs it, but because we introduced the duplication ourselves.&lt;/p&gt;




&lt;h3&gt;
  
  
  Two Sources of Truth
&lt;/h3&gt;

&lt;p&gt;One of the easiest ways to make a React component harder to reason about is introducing multiple sources of truth. Imagine this simpler 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;function&lt;/span&gt; &lt;span class="nf"&gt;UserCard&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDisplayName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setDisplayName&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;name&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="nx"&gt;user&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="nt"&gt;h2&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;displayName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&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;There are now two values representing the user's name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;user.name&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;displayName&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally they should always contain exactly the same value. The problem is that react doesn't know that, they're just two independent pieces of data and every time one changes, something has to update the other. That's exactly what the Effect is doing. The funny thing is that the Effect isn't adding any business logic. It's simply compensating for the fact that we duplicated state. Whenever I review code nowadays, I try spot these situations quickly because they're ofter a sign that the component is becoming more complex than it needs to be.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Bugs Usually don't Appear Immediately
&lt;/h3&gt;

&lt;p&gt;This is probably the biggest reason why this pattern is so common. The first version works pèrfectly and then somebody adds a feature.&lt;br&gt;
Maybe the input becomes editable.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;setDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still fine but a few weeks later another developer instroduces automatic refetching or optimistic updates or polling or live updates through WebSockets. Suddenly the Effect starts running much more often. Now imagine the user is typing while new data arrives from the server. Should the Effect overwrite what the user is writing? Should it ignore the update or should it merge both values?. At this point there isn't an obvious answer anymore. Not because React is difficult but because the component now owns two independent copies of the some data.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Component Is Solving the Wrong Problem
&lt;/h3&gt;

&lt;p&gt;One thing I've noticed after working on larger React application is that many Effets don't exist because the business logic is complicated. They exist because the component is trying to synchronize data that didn't need to be duplicated in the first place. That's an important distinction.&lt;br&gt;
The business rule here isn't complicated: "show the user's name". That's it. The complexity comes from maintaining two values that should never diverge. Once I started looking at Effects this way, I found myself deleting far more of them than writing new ones.&lt;/p&gt;


&lt;h3&gt;
  
  
  Most Components Don't Need Local State
&lt;/h3&gt;

&lt;p&gt;If the component only needs to display the data it receives, the simplest solution is usually the correct one.&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserCard&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="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&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="nt"&gt;p&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&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;
        &lt;span class="p"&gt;&amp;lt;/&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;There's no local state or synchronization or Effect. Every render simply reflects whatever the parent passed down. That's already how React works. Very often, adding local state doesn't make the component more flexible. It simply gives React another value that now has to stay synchronized.&lt;/p&gt;




&lt;h3&gt;
  
  
  Derived Values Don't Need State Either
&lt;/h3&gt;

&lt;p&gt;Antoher variation of the same problem looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsAdmin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsAdmin&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;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, there are now two sources of truth. But the second one doesn't even add new information, i'ts entirely derived from the first. Whenever I see this pattern nowadays, I usually replace it with a simple variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&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;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no Effect or state updates or extra render, just a value calculated during rendering. It's a tiny change, but after removing enough Effects like this, components become noticeably easier to understand.&lt;/p&gt;




&lt;h3&gt;
  
  
  Forms Are Usually the Exeption
&lt;/h3&gt;

&lt;p&gt;Whenever someone says &lt;em&gt;"don't sync props into state"&lt;/em&gt;, the first example that comes up is forms. And that's fair. Forms are probably the most common case where creating local state is the right decision. imagine an edit profile page, the server sends this object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;id:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;email:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user changes the name to Johnny, but hasn't clicked Save yet. At the moment there are actually two different pieces of information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the persisted user coming from the server&lt;/li&gt;
&lt;li&gt;the draft the user is editing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are not the same thing anymore. The mistake isn't copying the prop into state, but trying to keep both synchronized forever. Those values have different responsibilities. One represents the current server state and the other represents temporary UI state. Once you look at it that way, the problem becomes much clearer.&lt;/p&gt;




&lt;h3&gt;
  
  
  Initialize State once Instead of Synchronizing It Forever
&lt;/h3&gt;

&lt;p&gt;One thing I see surprisingly ofter is this:&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;function&lt;/span&gt; &lt;span class="nf"&gt;UserForm&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setName&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;name&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="nx"&gt;user&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 intention is understandable. Whenever a new user arrives, update the form. The problem is that every update to &lt;em&gt;user&lt;/em&gt; resets the input&lt;br&gt;
If the parent refetches data while the user is typing, their changes disappear. Instead, ask yourself a different question. Something like if you need to keep the form synchronized or do you need an initial value. Those are completely different requirements&lt;/p&gt;


&lt;h3&gt;
  
  
  Let React Reset the Component
&lt;/h3&gt;

&lt;p&gt;One of my favorite solutions is also one of the simplest. Instead of synchronizing state yourself, let React mount a fresh component.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserForm&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the component behaves naturally. The process looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open User A --&amp;gt; A new form is created --&amp;gt; Open User B --&amp;gt; React destroys the old form and creaters another one
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there's no synchronization Effect or manual reset or duplicated logic.&lt;br&gt;
Using &lt;em&gt;key&lt;/em&gt; intentionally like this is something I almost never did when I started with React, but nowadays it's often my first option.&lt;/p&gt;


&lt;h3&gt;
  
  
  Sometimes Local State Is the Right Tool
&lt;/h3&gt;

&lt;p&gt;Reading this article, it might sound like local state is something to avoid. But that's not the point at all. Local state is great, it's duplicated state that's usually the problem. If the local state represents something different form the incoming prop, then everything is perfectly fine.&lt;br&gt;
Some examples are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;editable forms&lt;/li&gt;
&lt;li&gt;wizard steps&lt;/li&gt;
&lt;li&gt;drag-and-drop interactions&lt;/li&gt;
&lt;li&gt;temporary filters&lt;/li&gt;
&lt;li&gt;undo/redo history&lt;/li&gt;
&lt;li&gt;optimistic UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these create state that intentionally diverges from the original prop. That's completely different from mirroring a prop just because we think we need to.&lt;/p&gt;


&lt;h3&gt;
  
  
  My Personal Rule
&lt;/h3&gt;

&lt;p&gt;Nowadays, whenever I catch myself writing this:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&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="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I stop for a second.&lt;br&gt;
Then I ask myself one question:&lt;br&gt;
&lt;strong&gt;Why does this component need its own copy of this value?&lt;/strong&gt;&lt;br&gt;
Sometimes there's a good answer but most of the times there isn't. Usually I realize that the component only needs to read the prop. Or maybe the value can be derived during rendering or perhaps React can reset the component naturally by changing its &lt;em&gt;key&lt;/em&gt;. That one question has probably saved me from writing dozens of unnecessary Effects.&lt;/p&gt;


&lt;h3&gt;
  
  
  Alternatives Before Reaching for useEffect
&lt;/h3&gt;

&lt;p&gt;When I review React code now, these are usually the alternatives I consider first:&lt;br&gt;
If the value can be calculated, derive it during render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&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;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the component only displays data, read it directly from props.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the component needs a fresh state for a different entity, remount it with a different &lt;em&gt;key&lt;/em&gt;.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserForm&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if the component genuinely needs a draft that diverges from the original data, then local state is absolutely the right choice. The important part is understanding why that local state exists.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Looking back, I don't think synchronizing props into state is a beginner mistake. I've seen it in production code written by experienced developers. Mostly because it works, until it doesn't. The issue isn't the Effect itself, it's that the Effect is often hiding a deeper problem, the component owns data it never needed to own. One thing I've learned over the years is that React code becomes much easier to reason about when every pierce of data has a single owner. As soon as multiple copies appear, synchronizition logic follws. And synchronizition logic almost always ends up inside a useEffect. Whenever I find myself writing an Effect that copies a prop into state, I now assume it's unnecessary until I can prove otherwise. Most of the time, deleting the Effect actually makes the component simpler.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Article in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/you-probably-dont-need-that-useeffect-event-handlers-are-usually-the-better-place-for-side-effect-4phf"&gt;Part 4: Event handlers are usually the better place for side effect&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-5-stop-using-effects-for-state-resets-4ado"&gt;Part 5: Stop Using Effects for State Resets&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Previous Articles in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f"&gt;Part 1: Why I Rarely Use useEffect Anymore (and what I use instead)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg"&gt;Part 2: Stop Fetching Data Inside useEffect (what modern React apps do instead)&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading!! If you're looking for help with an existing project or need someone to solve a tricky frontend/backend issue, you can also find my freelance profiles through my Dev.to profile.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>frontend</category>
      <category>coding</category>
    </item>
    <item>
      <title>Part 2: Stop Fetching Data Inside useEffect (what modern React apps do instead)</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Wed, 15 Jul 2026 08:33:13 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg</link>
      <guid>https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 2 of the &lt;strong&gt;Modern React Patterns&lt;/strong&gt; series&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous article (&lt;a href="https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f"&gt;Part 1: Why I Rarely Use useEffect Anymore (and what I use instead)&lt;/a&gt;) we looked at one of the most common reasons developers overuse useEffect: deriving state that React can already calculate during rendering.&lt;br&gt;
This time I'd like to talk about another pattern that I see in almost every React codebase I've worked on: fetching data inside useEffect.&lt;br&gt;
Just like derived state, this isn't technically wrong. In fact, it was the standard recommendation for years. Most of us learned React by writing data fetching exactly this way. The problem is that what starts as a perfectly reasonable solution, often becomes increasingly difficult to maintain as an application grows.&lt;/p&gt;


&lt;h3&gt;
  
  
  The Way We Learned
&lt;/h3&gt;

&lt;p&gt;If you've been writing React for a while, you've probably written something very similar to this.&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;function&lt;/span&gt; &lt;span class="nf"&gt;UsersPage&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="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="s2"&gt;/api/users&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&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="nx"&gt;setUsers&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UsersList&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&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;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's nothing fundamentally wrong with this component, but the request is made when the component mounts so the response is stored in state and the UI updates automatically. This works perfectly for a small application, but production applications rarely stays this simple.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Complexity Doesn't Appear Immediately
&lt;/h3&gt;

&lt;p&gt;One reason this pattern became so popular i that the first implementation is incredibly small. You write ten lines of code, the data appears on the screeen and you move on to the next feature. A few weeks later somebody asks for a loading spinner and then the backend starts returning validation errors so you need to retry failed requests.&lt;br&gt;
Eventually somebody reports that users sometimes navigate away before the request finishes and little by little, the component starts accumulating responsibilities that have nothing to do with rendering. This is an example of problems that I've seen and lived, all this story, in code language, ends up in something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&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;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&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="s2"&gt;/api/users&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;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;){&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Request failed&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AbortError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&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="nf"&gt;setLoading&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="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&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 alone isn't particularly complicated but the issue is that almost every API request in your application starts looking exactly like this.&lt;/p&gt;




&lt;h3&gt;
  
  
  Same Pattern Everywhere
&lt;/h3&gt;

&lt;p&gt;This is usually the point where the maintenance cost begins to show. Every page has a loading state, error state, request cancellation, retry logc and a duplicated fetch code.&lt;br&gt;
If your application has twenty different API endpoints, you'll probably have twenty very similar Effects. At first this feels harmless because each component only knows about its own request. Over time you realize you're solving the same problems over and over again. The code isn't becoming more complex because your business logic is difficult, but because every component is independently trying to solve data synchronization.&lt;/p&gt;


&lt;h3&gt;
  
  
  Shared Data Exposes the Problem
&lt;/h3&gt;

&lt;p&gt;Imagine your application has an authenticated user. The navigation bar, the profile page and also the settings page needs it. A common implementation looks something like this:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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="s2"&gt;/api/me&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&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="nx"&gt;setUser&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 component works, the next component copies the same Effect and then another one. Eventually three differents parts of the application are requesting exactly the same resource, even if the requests are fast, they're still duplicated work. More importantly, every component now owns its own loading state, its own error handling and its own copy of the fetched data; keeping everything synchronized becomes surprisingly difficult.&lt;/p&gt;




&lt;h3&gt;
  
  
  Server State Behavior
&lt;/h3&gt;

&lt;p&gt;This was probably the biggest shift in the way I think about React applications. For a long time I assumed I was managing React state but in reality I was managing server state. Those are completely different problems. React state belongs to your application and server state belongs somewhere else. I can become stale.&lt;br&gt;
Several components can depend on it simultaneously. It might already exist in memory but it may need background refreshes, retries after network failures and an optimistic updates after a mutation.&lt;br&gt;
None of those concerns are really about rendering components. They're about synchronizing your application with an external system.&lt;/p&gt;


&lt;h3&gt;
  
  
  That's Why Dedicated Libraries Exist
&lt;/h3&gt;

&lt;p&gt;Once I understood that distinction, my approach changed completely. Instead of treating every API call as another useEffect, I started using tools that are specifically designed for server state. For example, the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&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;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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="s2"&gt;/api/users&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&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="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&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;setLoading&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="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;can become this other code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isLoading&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="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fetchUsers&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 shorter syntax isn't the interesting part, but is everything that disappears. All the problems: Caching, deduplication, background refetching, retries, request cancellation and stale data management, have been solved by libraries such as TanStack Query. Instead of rebuilding thhose features in every component, you can focus on your application's actual behavior.&lt;/p&gt;




&lt;h3&gt;
  
  
  Use of useEffect
&lt;/h3&gt;

&lt;p&gt;useEffect is not wrong at all. I still fetch data inside an Effect from time to time. If I'm building an internal tool with one request, a quick prototype or a page that will probably never grow beyond a few hundred lines of code. In this cases adding another dependency often isn't worth it. The problem it's not using useEffect, is continuing to scale the same pattern after the application has clearly outgrown it.&lt;/p&gt;




&lt;h3&gt;
  
  
  My Personal Rule
&lt;/h3&gt;

&lt;p&gt;Nowadays I try to separate two completely different situations. If I'm synchronizing React with something external (a WebSocket connection, a timer, a browser event, a third-party SDK, etc.), useEffect is almost always the correct tool. But if I'm fetching data that lives on a server, I immediately think about server-state management instead.&lt;br&gt;
Making than distinction has dramatically reduced the number of Effects I write. More importantly, it has made my components much easier to read. Most of them are now focused almost entirely on rendering UI instead of coordinating network requests.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;One thing I've noticed over the years is that developers rarely overuse useEffect because they misunderstand React. Most of us simply learned React at a time when fetching data inside Effects was considered the normal approach. The ecosystem evolved, our applications became larger, libraries specialized in solving server-state problems became mature and our habits, however, often stayed the same.&lt;br&gt;
Looking back, reducing the amount of data fetching I perform inside useEffect has probably been one of the biggest improvements I've made to the way I structure React applications.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next Articles in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/part-3-stop-syncing-props-into-state-you-probably-dont-need-that-useeffect-2330"&gt;Part 3: Stop Syncing Props Into State&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/you-probably-dont-need-that-useeffect-event-handlers-are-usually-the-better-place-for-side-effect-4phf"&gt;Part 4: Event handlers are usually the better place for side effect&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-5-stop-using-effects-for-state-resets-4ado"&gt;Part 5: Stop Using Effects for State Resets&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Previous Article in This Series
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f"&gt;Part 1: Why I Rarely Use useEffect Anymore (and what I use instead)&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading!! If you're looking for help with an existing project or need someone to solve a tricky frontend/backend issue, you can also find my freelance profiles through my Dev.to profile.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Part 1: Why I Rarely Use useEffect Anymore (and what I use instead)</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Wed, 15 Jul 2026 07:26:46 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f</link>
      <guid>https://dev.to/alejandrodeveloper/why-i-rarely-use-useeffect-anymore-and-what-i-use-instead-ep1-423f</guid>
      <description>&lt;p&gt;When I started learning React, I thought useEffect was the solution to almost everything. To derive state, to fetch data, to synchronize props or calculate a value, the answer for all this was useEffect.&lt;br&gt;
After working on larger applications, i realized most of those effects weren't needed at all.&lt;br&gt;
Today, I probably write 80% fewer useEffects than I did a few years ago. Not because it's a bad hook but because most problems have simpler solutions.&lt;br&gt;
This article is the first part of my &lt;strong&gt;Modern React Patterns&lt;/strong&gt; series, where I go over patterns that worked fine in small demos but became painful in production.&lt;/p&gt;


&lt;h3&gt;
  
  
  What useEffect Is Actually For
&lt;/h3&gt;

&lt;p&gt;The React documentation describes effects as a way to synchronize your component with external systems.&lt;br&gt;
That means things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;network requests&lt;/li&gt;
&lt;li&gt;WebSockets&lt;/li&gt;
&lt;li&gt;timers&lt;/li&gt;
&lt;li&gt;browser APIs&lt;/li&gt;
&lt;li&gt;subscriptions&lt;/li&gt;
&lt;li&gt;third-party libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your effect isn't interacting with something outside React, there's a good chance you don't need one.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Don't Use useEffect For
&lt;/h3&gt;

&lt;p&gt;One of the most common examples I still see is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFullName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setFullName&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;firstName&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;lastName&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;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works but React now renders twice. The process that now is doing is the following:&lt;br&gt;
render --&amp;gt; effect runs --&amp;gt; state changes --&amp;gt; render again&lt;br&gt;
and there's no reason for that.&lt;/p&gt;

&lt;p&gt;Instead i do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="o"&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;firstName&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;lastName&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;h3&gt;
  
  
  2. Don't Synchronize Props Into State
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setuser&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="nx"&gt;user&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="nx"&gt;props&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of the times this creates two sources of truth. Eventually one of them gets updated and the other doesn't. Unless you intentionally want a local editable copy, just use the prop directly. It's much simpler&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;function&lt;/span&gt; &lt;span class="nf"&gt;prodile&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Don't Calculate Values Inside an Effect
&lt;/h3&gt;

&lt;p&gt;I've seen code like this many times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filteredUsers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFilteredUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;useStat&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setFilteredUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&amp;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;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's unnecessary state, i'ts way better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredUsers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&amp;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;active&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the computation is actually expensive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredUsers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&amp;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;active&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="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that useMemo is an optimization, not a replacement for every calculation.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Debugging Is One of The Few Places Where I Still Use Effects A Lot
&lt;/h3&gt;

&lt;p&gt;When debugging state updates I often do this:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;user&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's incredibly useful while debugging but before merging the code, delete it.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Fetching Data With useEffect Isn't Always The Best Choice Anymore
&lt;/h3&gt;

&lt;p&gt;Years ago almost every React project looked like this:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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="s2"&gt;/api/users&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&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="nx"&gt;setUsers&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;Nowadays we have much better alternatives. Libraries like TanStack Query or SWR solve things that you eventually end up building yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;caching&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;background refetching&lt;/li&gt;
&lt;li&gt;loading state&lt;/li&gt;
&lt;li&gt;error state&lt;/li&gt;
&lt;li&gt;deduplication
And instead of all of this, you can:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getUsers&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's less code and you get fewer bugs and better developer experience.&lt;/p&gt;

&lt;p&gt;If you're interested in API reliability, I wrote another article about common integration mistakes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/building-reliable-api-integrations-in-modern-web-application-1hg5"&gt;"Building Reliable API integrations in Modern Web Applications"&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Effects Often Hide Architecture Problems
&lt;/h3&gt;

&lt;p&gt;Something I've noticed over time is whenever I find myself writing lots of effects indife the same component and it's usually because the component is trying to do too much. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetching&lt;/li&gt;
&lt;li&gt;filtering&lt;/li&gt;
&lt;li&gt;sorting&lt;/li&gt;
&lt;li&gt;formatting&lt;/li&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;event handling&lt;/li&gt;
&lt;li&gt;rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and everything together. Splitting responsabilities into smaller hooks or components ofter removes half of those effects automatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  When You SHOULD Use useEffect
&lt;/h3&gt;

&lt;p&gt;None of this means "never use useEffect". There are plenty of legitimate use cases to use it, and let me tell some of them.&lt;br&gt;
WebSocket connections:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;Timers:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;Browser APIs:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onResize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onResize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Third-party libraries:&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Chart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&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;These are exactly the kinds of external systems effects were designed for.&lt;/p&gt;




&lt;h3&gt;
  
  
  My Personal Rule
&lt;/h3&gt;

&lt;p&gt;Whenever I'm about to write an effect, I stop for a second and ask myself if am I synchronizing with an external system or am I compensating for my component design. That question alone has removed a surprising amount of unnecessary code from my projects.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;useEffect isn't bad. It's just much easier to overuse than most React hooks. Today I try to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;derived values instead of derived state&lt;/li&gt;
&lt;li&gt;props instead of synchronized state&lt;/li&gt;
&lt;li&gt;TanStack Query for server state&lt;/li&gt;
&lt;li&gt;custom hooks for reusable logic&lt;/li&gt;
&lt;li&gt;effects only when I actually need to synchronize with something outside React&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And you can get fewer renders, less state, fewer bugs and components that are easier to understand months later.&lt;/p&gt;




&lt;h4&gt;
  
  
  Next Articles in This Series
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://dev.to/alejandrodeveloper/part-2-stop-fetching-data-inside-useeffect-what-modern-react-apps-do-instead-lg"&gt;Part 2: Stop Fetching Data Inside useEffect&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-3-stop-syncing-props-into-state-you-probably-dont-need-that-useeffect-2330"&gt;Part 3: Stop Syncing Props Into State&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/you-probably-dont-need-that-useeffect-event-handlers-are-usually-the-better-place-for-side-effect-4phf"&gt;Part 4: Event handlers are usually the better place for side effect&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/alejandrodeveloper/part-5-stop-using-effects-for-state-resets-4ado"&gt;Part 5: Stop Using Effects for State Resets&lt;/a&gt;&lt;/p&gt;










&lt;p&gt;Thanks for reading!! If you're looking for help with an existing project or need someone to solve a tricky frontend/backend issue, you can also find my freelance profiles through my Dev.to profile.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Angular performance optimization: change detection mistakes you should avoid</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Fri, 03 Jul 2026 14:59:05 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/angular-performance-optimization-change-detection-mistakes-you-should-avoid-3g8b</link>
      <guid>https://dev.to/alejandrodeveloper/angular-performance-optimization-change-detection-mistakes-you-should-avoid-3g8b</guid>
      <description>&lt;p&gt;Angular apps can stay fast for a long time, until they don't. A lot of performance issues i've debugged had nothing to do with bundle size or server speed. The real problem was change detection doing way more work than it needed.&lt;br&gt;
Here are some common mistakes.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Using the default strategy everywhere
&lt;/h3&gt;

&lt;p&gt;Angular's default change detection is convenient, but it checks more often than many apps actually need. For bigger applications, this can become expensive fast. Using &lt;code&gt;OnPush&lt;/code&gt; in the right places can reduce unnecessary updates a lot.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Calling functions directly in templates
&lt;/h3&gt;

&lt;p&gt;This one is easy to miss. every detection cycle will execute those functions again. If the function is expensive or creates new objects, performance can drop quickly.&lt;br&gt;
Computed values should usually live outside the template.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Mutating objects with OnPush
&lt;/h3&gt;

&lt;p&gt;A common mistake. With &lt;code&gt;OnPush&lt;/code&gt;, Angular watches references, not deep changes. Mutating and existing object can prevent updates from rendering. Immutable updates make this much more prefictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Rendering large lists without trackBy
&lt;/h3&gt;

&lt;p&gt;Without &lt;code&gt;trackBy&lt;/code&gt;, Angular may recreate DOM elements unnecessarily. On big lists, that gets expensive. A simple &lt;code&gt;trackBy&lt;/code&gt; can save a lot of work.&lt;/p&gt;




&lt;p&gt;Most Angular performance problems are not caused by Angular. They usually come from small patterns repeated across the app. And change detection is often where those patterns hurt the most.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>performance</category>
      <category>frontend</category>
      <category>development</category>
    </item>
    <item>
      <title>How to optimize Angular bundle size for faster load times</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Fri, 03 Jul 2026 14:45:07 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/how-to-optimize-angular-bundle-size-for-faster-load-times-3f28</link>
      <guid>https://dev.to/alejandrodeveloper/how-to-optimize-angular-bundle-size-for-faster-load-times-3f28</guid>
      <description>&lt;p&gt;One of the most common problems I see in Angular projects is bundle size growing way faster than expected.&lt;br&gt;
At first, everything feels fine, then the app grows, dependencies pile up and suddenly your first load is slow, your Lighthouse score drops and users start noticing.&lt;br&gt;
Here are some practical ways to optimize Angular bundle size.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Lazy load everything that makes sense
&lt;/h3&gt;

&lt;p&gt;A lot of apps still ship too much code upfront.&lt;br&gt;
Feature modules, admin panels, dashboards or rarely used routes should be lazy loaded so users only download what they need. This alone can make a huge difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Audit third-party dependencies
&lt;/h3&gt;

&lt;p&gt;Some libraries look small but pull in a lot of extra code. Date libraries, UI kits and utility packages are usually the biggest offenders. Always check if you really need the whole package.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Whatch for duplicated imports
&lt;/h3&gt;

&lt;p&gt;It's easy to accidentally import the same heavy dependency in multiple places. This can bloat the final bundle more than expected. Bundle analyzers help a lot here.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Use standalone components when possible
&lt;/h3&gt;

&lt;p&gt;Angular's newer architecture can reduce unnecessary module overhead and improve tree-shaking&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Optimize assets too
&lt;/h3&gt;

&lt;p&gt;Images, fonts and icons are part of your load time. A perfectly optimized Js bundle can still feel slow if assets are heavy&lt;/p&gt;




&lt;p&gt;Most Angular performance issues don't come from Angular itself. They come from how the app grows. Bundle size is one of the first places where that shows up.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>performance</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Why API integrations break when your app scales</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Fri, 03 Jul 2026 10:36:58 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/why-api-integrations-break-when-your-app-scales-27hl</link>
      <guid>https://dev.to/alejandrodeveloper/why-api-integrations-break-when-your-app-scales-27hl</guid>
      <description>&lt;p&gt;API integrations usually feel easy at the beginning. A few requests, some authentications, maybe a webhook or two and everything works fine. Then your app grows; more users, more traffic, more concurrent requests, more dependencies. That's when things start breaking.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Rate limits hit faster than expected
&lt;/h3&gt;

&lt;p&gt;What worked for 50 users suddenly fails at 5000.&lt;br&gt;
Without queues, batching or retry strategies, external APIs can quickly become bottlenecks.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Small delays become big problems
&lt;/h3&gt;

&lt;p&gt;At scale, even small latency from third-party APIs adds up. One slow dependency can affect the whole user flow. This is why timeouts and fallback strategies matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Token management gets harder
&lt;/h3&gt;

&lt;p&gt;More users means more sessions, more refreshes and more chances for auth flows to fail. Bad token rotation logic becomes a real problem fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Error handling becomes architecture
&lt;/h3&gt;

&lt;p&gt;At small scale, you can fix things manually. At bigger scale, every failure needs to be predictable. Logging, monitoring and graceful recovery stop being optional. Scaling an app doesn't just expose performance issues. It exposes weak integrations. An most teams realize it later than they should.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>Building reliable API integrations in modern web application</title>
      <dc:creator>Alejandro</dc:creator>
      <pubDate>Fri, 03 Jul 2026 10:16:55 +0000</pubDate>
      <link>https://dev.to/alejandrodeveloper/building-reliable-api-integrations-in-modern-web-application-1hg5</link>
      <guid>https://dev.to/alejandrodeveloper/building-reliable-api-integrations-in-modern-web-application-1hg5</guid>
      <description>&lt;p&gt;Modern applications depend on APIs more than ever.&lt;br&gt;
Payments, authentication, notifications, analytics, CRMs... most products today rely on multiple third-party services to function properly. Connecting them is usually the easy part.&lt;br&gt;
Making them reliable is where things get difficult.&lt;br&gt;
A lot of API integrations work perfectly during development, but start failing once real users, real traffic and edge cases show up.&lt;br&gt;
Here are some of the most common problemns I keep seeing.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Third-party failures are normal
&lt;/h3&gt;

&lt;p&gt;External APIs fail. Timeouts happen. Servers go down. Responses get delayed. If your app assumes every request will succeed, it will eventually break. Retries, fallbacks and proper error handling should be part of the architecture from day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Authentication gets messy fast
&lt;/h3&gt;

&lt;p&gt;Expired tokens, refresh logic, invalid sessions and revoked credentials create a lot of hidden problems.&lt;br&gt;
A secure auth flows is not just about getting a token. It's about handling the full lifecycle correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. APIs change over time
&lt;/h3&gt;

&lt;p&gt;Response structures evolve. Fields get renamed, removed or changed.&lt;br&gt;
Without validation and version control, even small changes can break critical features.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Rate limits become real at scale
&lt;/h3&gt;

&lt;p&gt;What works with 10 users may fail with 10000. Batching, queues and backoff strategies become necessary much earlier than most teams expect.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
