<?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: Fernando Villalba</title>
    <description>The latest articles on DEV Community by Fernando Villalba (@falcondpr).</description>
    <link>https://dev.to/falcondpr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3244547%2F2f4ec845-5af9-4067-9022-90dd9af5f499.jpg</url>
      <title>DEV Community: Fernando Villalba</title>
      <link>https://dev.to/falcondpr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/falcondpr"/>
    <language>en</language>
    <item>
      <title>Is there a silent bug in your useEffect?</title>
      <dc:creator>Fernando Villalba</dc:creator>
      <pubDate>Tue, 07 Apr 2026 18:59:29 +0000</pubDate>
      <link>https://dev.to/falcondpr/is-there-a-silent-bug-in-your-useeffect-1fi5</link>
      <guid>https://dev.to/falcondpr/is-there-a-silent-bug-in-your-useeffect-1fi5</guid>
      <description>&lt;p&gt;Rapid changes in searches or navigation generate multiple simultaneous requests. Without control, the response that arrives last (even if it contains obsolete data) will overwrite the state, displaying incorrect information. A silent but critical error.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Race Conditions
&lt;/h2&gt;

&lt;p&gt;When the order of responses does not match the order of requests.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipjp39bqvr2u1kztfohv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipjp39bqvr2u1kztfohv.png" alt="Visual example of the amount of requests" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Common Code (The Error)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Click A → "Data A" is requested&lt;/li&gt;
&lt;li&gt; Click B → "Data B" is requested&lt;/li&gt;
&lt;li&gt; Network: B arrives (Fast) → UI shows "Data B" ✓&lt;/li&gt;
&lt;li&gt; Network: A arrives (Late) → UI overwrites with "Data A" ✗&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even though the user clicked B last and wants to see those data, the interface ends up showing obsolete information from A. This happens because each request updates the state without verifying if it is still relevant.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution (AbortController)
&lt;/h2&gt;

&lt;p&gt;The key to solving this is canceling the previous request before firing the new one. The native AbortController API allows us to do this elegantly:&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;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="c1"&gt;// 1. We create the controller&lt;/span&gt;

  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&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="s2"&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="c1"&gt;// 2. We pass the signal&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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;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;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="s1"&gt;AbortError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We handle only real errors, not cancellations&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Cleanup function: we cancel if the component&lt;/span&gt;
  &lt;span class="c1"&gt;// unmounts or the ID changes&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;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Does your useEffect have a silent bug?</title>
      <dc:creator>Fernando Villalba</dc:creator>
      <pubDate>Tue, 07 Apr 2026 18:56:44 +0000</pubDate>
      <link>https://dev.to/falcondpr/does-your-useeffect-have-a-silent-bug-6ah</link>
      <guid>https://dev.to/falcondpr/does-your-useeffect-have-a-silent-bug-6ah</guid>
      <description>&lt;p&gt;Rapid changes in searches or navigation generate multiple simultaneous requests. Without control, the response that arrives last (even if it contains obsolete data) will overwrite the state, displaying incorrect information. A silent but critical error.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Race Conditions
&lt;/h2&gt;

&lt;p&gt;When the order of responses does not match the order of requests.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipjp39bqvr2u1kztfohv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipjp39bqvr2u1kztfohv.png" alt="Ejemplo visual explicando el error de solicitud de llamadas" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Common Code (The Error)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Click A → "Data A" is requested&lt;/li&gt;
&lt;li&gt; Click B → "Data B" is requested&lt;/li&gt;
&lt;li&gt; Network: B arrives (Fast) → UI shows "Data B" ✓&lt;/li&gt;
&lt;li&gt; Network: A arrives (Late) → UI overwrites with "Data A" ✗&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even though the user clicked B last and wants to see those data, the interface ends up showing obsolete information from A. This happens because each request updates the state without verifying if it is still relevant.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution (AbortController)
&lt;/h2&gt;

&lt;p&gt;The key to solving this is canceling the previous request before firing the new one. The native AbortController API allows us to do this elegantly:&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;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="c1"&gt;// 1. We create the controller&lt;/span&gt;

  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&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="s2"&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="c1"&gt;// 2. We pass the signal&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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;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;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="s1"&gt;AbortError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We handle only real errors, not cancellations&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Cleanup function: we cancel if the component&lt;/span&gt;
  &lt;span class="c1"&gt;// unmounts or the ID changes&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;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>¿Tu useEffect tiene un bug silencioso?</title>
      <dc:creator>Fernando Villalba</dc:creator>
      <pubDate>Tue, 07 Apr 2026 15:27:36 +0000</pubDate>
      <link>https://dev.to/falcondpr/tu-useeffect-tiene-un-bug-silencioso-9cf</link>
      <guid>https://dev.to/falcondpr/tu-useeffect-tiene-un-bug-silencioso-9cf</guid>
      <description>&lt;p&gt;Cambios rápidos en búsquedas o navegación generan múltiples peticiones simultáneas. Sin control, la respuesta que llegue última (aunque sea para datos obsoletos) sobrescribirá el estado, mostrando información incorrecta. Un error silencioso pero crítico.&lt;/p&gt;

&lt;h2&gt;
  
  
  El Problema: Race Conditions
&lt;/h2&gt;

&lt;p&gt;Cuando el orden de las respuestas no coincide con el de las peticiones.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipjp39bqvr2u1kztfohv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipjp39bqvr2u1kztfohv.png" alt="Ejemplo visual explicando el error de solicitud de llamadas" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  El Código Común (El error)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Click A → Se solicita "Datos A"&lt;/li&gt;
&lt;li&gt;Click B → Se solicita "Datos B"&lt;/li&gt;
&lt;li&gt;Red: Llega B (Rápido) → UI muestra "Datos B" ✓&lt;/li&gt;
&lt;li&gt;Red: Llega A (Tarde) → UI sobrescribe con "Datos A" ✗&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aunque el usuario hizo clic en B último y quiere ver esos datos, la interfaz termina mostrando información obsoleta de A. Esto sucede porque cada petición actualiza el estado sin verificar si sigue siendo relevante.&lt;/p&gt;
&lt;h2&gt;
  
  
  La Solución (AbortController)
&lt;/h2&gt;

&lt;p&gt;La clave para solucionar esto es cancelar la petición anterior antes de disparar la nueva. La API nativa AbortController nos permite hacer esto de forma elegante:&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;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="c1"&gt;// 1. Creamos el controlador&lt;/span&gt;

  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&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="s2"&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="c1"&gt;// 2. Pasamos la señal&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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;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;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="s1"&gt;AbortError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Manejamos solo errores reales, no cancelaciones&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="c1"&gt;// 3. Función de limpieza: cancelamos si el componente&lt;/span&gt;
  &lt;span class="c1"&gt;// se desmonta o el ID cambia&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;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
