<?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: Nikhil Sharma</title>
    <description>The latest articles on DEV Community by Nikhil Sharma (@nikhilsharma6).</description>
    <link>https://dev.to/nikhilsharma6</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%2F3222504%2F0c35495e-0c52-43f3-a92d-07854e3cd0e0.jpg</url>
      <title>DEV Community: Nikhil Sharma</title>
      <link>https://dev.to/nikhilsharma6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikhilsharma6"/>
    <language>en</language>
    <item>
      <title>Why I Chose a Dual Protocol Architecture: REST + WebSockets</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Thu, 25 Jun 2026 06:50:51 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/why-i-chose-a-dual-protocol-architecture-rest-websockets-4co0</link>
      <guid>https://dev.to/nikhilsharma6/why-i-chose-a-dual-protocol-architecture-rest-websockets-4co0</guid>
      <description>&lt;p&gt;When I first started building the real-time chat features for my project, the initial architectural decisions seemed quite simple to me. It was going to be a "real-time" app so 'obviously' I needed WebSockets. My first instinct was to use a socket event for everything whether it be authentication or even loading chat history.&lt;br&gt;
Eventually, I read some articles pertaining to the same and then shifted to the dual architecture which is in place now. Which is REST+WebSockets and using each protocol for what its good at. &lt;/p&gt;
&lt;h2&gt;
  
  
  The common first thought
&lt;/h2&gt;

&lt;p&gt;It is incredibly tempting to establish a WebSocket connection and route the entire application state through it. It feels clean to have a single pipe to the server. &lt;/p&gt;

&lt;p&gt;But I quickly ran into the architectural realities of stateful WebSocket connections. While they are good for maintaining persistent duplex connections, they provide a much lower-level transport abstraction than HTTP.&lt;/p&gt;

&lt;p&gt;On fetching the older chat history, I immediately missed standard HTTP status codes. If a request failed, I had to myself make my own error-handling payload structure as there was no automated 404 or 401 code being sent. As in WebSockets, after a connection is established, there are no HTTP responses, its all just messages. So I lost out on all standard HTTP semantics, which meant a lot more work for me.&lt;/p&gt;

&lt;p&gt;WebSockets are inherently stateful which makes load balancing and scaling much more complex, each connection has to stay attached to a server, so horizontally scaling requires connection-aware load balancing and some shared mechanism (such as Redis Pub-Sub) to broadcast events across instances as compared to spinning up stateless REST APIs behind a standard reverse proxy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Not Just HTTP Polling?
&lt;/h2&gt;

&lt;p&gt;On the other end of the spectrum I very briefly considered avoiding WebSockets entirely. Why not just use REST for everything and implement polling?&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;// The classic polling trap&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;startPolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setInterval&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="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;newMessages&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/rooms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/messages?since=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastTimestamp&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="c1"&gt;// Handle new messages...&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue with polling became apparent the moment I thought about the user experience and server load. With short polling I would be sending HTTP requests every few seconds. And 90% of the time the server's response would be an empty array because no new messages had arrived. This results in massive HTTP overhead, unnecessary server strain and an inherent latency equal to the polling interval, which I just did not like seeing when I tested a dummy app.&lt;/p&gt;

&lt;p&gt;Even long-polling (where the server holds the request open until a message arrives) felt like a hacky workaround to simulate the persistent connection that WebSockets natively provide. &lt;/p&gt;

&lt;p&gt;And so I instantly knew that polling, long or short, is not an option for my case.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ideal Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            React Client
                 │
      ┌──────────┴──────────┐
      │                     │
      ▼                     ▼
 REST (Request/Response)   WebSocket (Events)
      │                     │
      │                     │
 Load state            Live updates
(Login, Users,         (Messages,
 History, etc.)        Typing, Presence)
      └──────────┬──────────┘
                 ▼
         Backend + Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I eventually landed on a dual-protocol approach. The mechanism was easy to understand, anything that is coming out of the database(essentially older stuff) comes from the HTTP side of things, anything realtime comes from the WS side of things.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. REST for initial state
&lt;/h3&gt;

&lt;p&gt;I use standard REST endpoints for operations that follow a Request-Response model. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetching a user's profile.&lt;/li&gt;
&lt;li&gt;Fetching the list of users.&lt;/li&gt;
&lt;li&gt;Loading the initial chat history for an open chat.&lt;/li&gt;
&lt;li&gt;Authenticating the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By doing this I could keep my backend mostly stateless for the heavy queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. WebSockets for the Real-Time Pipeline
&lt;/h3&gt;

&lt;p&gt;Once the static state is loaded via REST, I open a WebSocket connection strictly as an event pipeline. The socket's only job is to push real-time events from the server to the client.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;new message&lt;/li&gt;
&lt;li&gt;typing event&lt;/li&gt;
&lt;li&gt;isOnline event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simplified snippet(not from the codebase because there is a lot of other stuff going on there) of how I orchestrate this dual approach when a user enters a chat room:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;enterChatRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Fetch the static history via REST&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;response&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/rooms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/history`&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to load history&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;pastMessages&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;response&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="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pastMessages&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;handleRestError&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="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Open the WebSocket strictly for real-time events&lt;/span&gt;
  &lt;span class="c1"&gt;// We get low-latency, bi-directional communication without HTTP overhead&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`wss://api.myproject.com/rooms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/live`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &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="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NEW_MESSAGE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setMessages&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="nx"&gt;prev&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;message&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USER_TYPING&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;showTypingIndicator&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;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Building this project taught me that just because a technology &lt;em&gt;can&lt;/em&gt; do something doesn't mean it &lt;em&gt;should&lt;/em&gt;. WebSockets are an incredible tool for real-time, low-latency communication, but they are a poor substitute for the robust, heavily-standardized world of RESTful HTTP. &lt;/p&gt;

&lt;p&gt;By utilizing a dual-protocol architecture, I avoided the heavy overhead of HTTP polling while simultaneously saving myself from the nightmare of reinventing routing, caching, and error handling over a raw socket connection. &lt;/p&gt;

&lt;p&gt;I'll be back with more next week. Till then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>The Stale Closure Bug That Haunted My Chat App</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Sun, 14 Jun 2026 05:53:19 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/the-stale-closure-bug-that-haunted-my-chat-app-khp</link>
      <guid>https://dev.to/nikhilsharma6/the-stale-closure-bug-that-haunted-my-chat-app-khp</guid>
      <description>&lt;p&gt;Building a real-time chat app sounds straightforward until React's rendering model meets WebSockets . In Relay, I built what I thought was a solid real-time integration. Everything seemed to work perfectly—until I started switching between conversations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;In Relay, I wanted a clean separation of concerns, so I extracted my WebSocket logic into a custom hook called useWebSocket. It takes an onMessage callback so my Chat UI can decide how to handle incoming messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Chat.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sendMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useWebSocket&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&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;// If the message is from the person I'm actively chatting with, add it to the window&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;selectedUser&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;senderId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;selectedUser&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="nf"&gt;addMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Otherwise, show a toast notification&lt;/span&gt;
  &lt;span class="nf"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside useWebSocket.ts, I wired up the actual WebSocket connection inside a useEffect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useWebSocket.ts (The broken version)&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;useWebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;WS_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;receive_message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Only reconnect if the authenticated user changes&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Broke
&lt;/h2&gt;

&lt;p&gt;At first glance, this code looks entirely reasonable. I'd open Relay, click on Alice's profile, and we'd start chatting. It worked flawlessly.&lt;/p&gt;

&lt;p&gt;Then, I'd switch my active chat to Bob. Bob would send me a message, but instead of the message appearing in Bob's chat window, a toast notification would pop up. Even worse, if Alice sent me a message while I was looking at Bob's chat, her message silently injected itself directly into Bob's chat window!&lt;/p&gt;

&lt;p&gt;I was literally watching the messages of one user show up in another user's chat after I switched.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Broke (The Mental Model)
&lt;/h2&gt;

&lt;p&gt;The culprit was a classic React gotcha: the stale closure.&lt;/p&gt;

&lt;p&gt;When the useWebSocket hook ran for the first time, the useEffect established the WebSocket connection. The socket.onmessage event listener was created, and it permanently "captured" the onMessage function from that specific initial render.&lt;/p&gt;

&lt;p&gt;In that first render, selectedUser was Alice.&lt;/p&gt;

&lt;p&gt;When I clicked on Bob in the sidebar, React re-rendered my Chat component. A brand new onMessage function was created where selectedUser was Bob. However, because my useEffect dependency array only included &lt;a href="https://dev.tothe%20logged-in%20auth%20user,%20not%20the%20selected%20chat%20partner"&gt;user&lt;/a&gt;, the effect didn't re-run. The WebSocket stayed connected—which is what we want.&lt;/p&gt;

&lt;p&gt;But this meant the socket.onmessage listener was still holding onto the very first onMessage function it captured—the one where selectedUser is permanently frozen as Alice.&lt;/p&gt;

&lt;p&gt;If I simply added onMessage to the useEffect dependency array to fix the stale state, the WebSocket would brutally disconnect and reconnect every single time I clicked a new user, typed a character, or triggered a re-render. That's terrible UX and a massive performance killer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useRef Fix
&lt;/h2&gt;

&lt;p&gt;I needed a way for the WebSocket listener to always access the freshest version of the onMessage callback, without actually triggering the useEffect to tear down the socket.&lt;/p&gt;

&lt;p&gt;Enter useRef.&lt;/p&gt;

&lt;p&gt;Unlike state, updating a ref doesn't trigger a re-render. More importantly, a ref is a mutable object that persists across renders. By continuously storing the latest callback in a ref, the WebSocket listener can just peek into ref.current and always find the most up-to-date function.&lt;/p&gt;

&lt;p&gt;Here is the exact code that fixed the bug in Relay:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useWebSocket.ts (The fixed version)&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;useWebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Create a ref to hold the callback&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onMessageRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. Silently update the ref every time the callback changes (on every render)&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;onMessageRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onMessage&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;onMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;WS_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;receive_message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Always call the freshest callback stored in the ref!&lt;/span&gt;
        &lt;span class="nx"&gt;onMessageRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Whenever you integrate long-lived event listeners (like WebSockets, window events, or setInterval) with React components, you have to be paranoid about what variables are being captured in their closures. If you need access to constantly changing React state inside a permanent event listener, the useRef escape hatch is your best friend.&lt;/p&gt;

&lt;p&gt;I'll be back with more next week. Until then, stay consistent!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sidenote
&lt;/h2&gt;

&lt;p&gt;Relay is now live: &lt;a href="https://relay.nikshrma.dev" rel="noopener noreferrer"&gt;https://relay.nikshrma.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's running on a DigitalOcean droplet and has been a great playground for learning WebSockets, authentication, testing, and deployment.&lt;/p&gt;

&lt;p&gt;You can also find my portfolio at &lt;a href="https://nikshrma.dev" rel="noopener noreferrer"&gt;https://nikshrma.dev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The WebSocket Auth Problem: Cookies vs. Bearer Tokens</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Wed, 03 Jun 2026 20:23:14 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/the-websocket-auth-problem-cookies-vs-bearer-tokens-4eel</link>
      <guid>https://dev.to/nikhilsharma6/the-websocket-auth-problem-cookies-vs-bearer-tokens-4eel</guid>
      <description>&lt;p&gt;If you've ever built a real-time web app using WebSockets, you've probably hit this exact wall - how do I do the auth.&lt;/p&gt;

&lt;p&gt;On the HTTP side, the answer is pretty simple. You either use a cookie, which has so many npm packages, or you attach an &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header to your requests, which is a simple JWT signed string. However, things get a bit weird on the WebSocket side of things.&lt;/p&gt;

&lt;p&gt;The fundamental issue stems from how WebSocket connections are established. Before a WebSocket connection becomes a continuous bidirectional channel of data, it starts off as a simple HTTP &lt;code&gt;GET&lt;/code&gt; request with an &lt;code&gt;Upgrade&lt;/code&gt; header. This is known as the WebSocket Handshake.&lt;/p&gt;

&lt;p&gt;Let's dive into why this handshake makes the seemingly simple task of authentication a surprisingly nuanced architectural decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Bearer Tokens are Clunky for WebSockets
&lt;/h2&gt;

&lt;p&gt;If your application relies on Bearer tokens (usually stored in memory or local storage on the client side), you are used to attaching them via the &lt;code&gt;Authorization&lt;/code&gt; header using an interceptor or a fetch wrapper.&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;// A typical HTTP request with a Bearer token&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="s1"&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;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;myToken&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the native browser &lt;code&gt;WebSocket&lt;/code&gt; API &lt;strong&gt;does not support custom headers&lt;/strong&gt;.&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;// This is all we get.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://api.myapp.com/socket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you can't pass the token in an &lt;code&gt;Authorization&lt;/code&gt; header during the initial HTTP Upgrade request, developers are forced into clunky workarounds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query Parameters&lt;/strong&gt;: Passing the token in the URL (&lt;code&gt;wss://api.myapp.com/socket?token=ey...&lt;/code&gt;). This is generally considered a bad practice because URLs (and the sensitive tokens within them) end up in server logs, browser histories, and proxy logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First Message Auth&lt;/strong&gt;: Opening the WebSocket connection unauthenticated, and then requiring the client to immediately send an authentication message containing the token before the server accepts any further messages. While secure, this adds latency and complexity to the connection lifecycle logic. You have to write boilerplate to handle connections that open but never authenticate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subprotocols&lt;/strong&gt;: A hacky but working method where the token is passed as a WebSocket subprotocol (&lt;code&gt;new WebSocket('wss://...', ['access_token', token])&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these feel particularly clean or idiomatic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Cookies Work Naturally
&lt;/h2&gt;

&lt;p&gt;This brings us to cookies, the method that I chose for &lt;a href="https://github.com/nikshrma/relay" rel="noopener noreferrer"&gt;Relay&lt;/a&gt;! Cookies are managed by the browser. Whenever the browser makes an HTTP request to a domain, it automatically attaches the cookies associated with that domain.&lt;/p&gt;

&lt;p&gt;Because the WebSocket handshake is just a standard HTTP &lt;code&gt;GET&lt;/code&gt; request, &lt;strong&gt;the browser automatically includes your cookies&lt;/strong&gt; in the first request itself!&lt;/p&gt;

&lt;p&gt;If your authentication system sets an HTTP-only cookie containing your JWT or session ID when the user logs in, you literally don't have to change any client-side code to authenticate your WebSockets. The browser handles it natively and securely.&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;// The browser automatically attaches the JWT auth cookie!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://api.myapp.com/socket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Backend Implementation: Parsing the Cookie
&lt;/h2&gt;

&lt;p&gt;While the client side becomes trivial, the backend need manual cookie parsing. When your WebSocket server receives the &lt;code&gt;upgrade&lt;/code&gt; request, it hands you a raw Node.js &lt;code&gt;IncomingMessage&lt;/code&gt; object. &lt;/p&gt;

&lt;p&gt;Unlike Express requests which come with the &lt;code&gt;cookies&lt;/code&gt; objects provided by middleware, the &lt;code&gt;IncomingMessage&lt;/code&gt; just gives you the raw &lt;code&gt;cookie&lt;/code&gt; header string. You have to parse it yourself before accepting the WebSocket connection.&lt;/p&gt;

&lt;p&gt;Below is how I did the cookie parsing in Relay!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Extracting and Verifying the Token
&lt;/h3&gt;

&lt;p&gt;First, we need a utility function to take the raw &lt;code&gt;IncomingMessage&lt;/code&gt;, parse the cookie string, and verify our JWT.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cookie&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;cookie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&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;jsonwebtoken&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IncomingMessage&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;http&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;jwtPayloadSchema&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;../../http/schemas/auth.schema.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Extract user ID from the raw HTTP upgrade request&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;extractUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IncomingMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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="c1"&gt;// Parse the raw cookie header string&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;cookie&lt;/span&gt; &lt;span class="o"&gt;??&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookies&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="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;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Verify the JWT signature&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Validate the payload shape&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwtPayloadSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decoded&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;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Return the authenticated User ID&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;parsed&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;id&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Token is invalid or expired&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. The main Socket handling code
&lt;/h3&gt;

&lt;p&gt;Now here, I integrate this utility into my WebSocket server initialisation. I intercept the connection, attempt to extract the user ID, and immediately close the connection with a &lt;code&gt;4001 Unauthorized&lt;/code&gt; status if the authentication fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebSocketServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&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;ws&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HttpServer&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;http&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;extractUserId&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;./handlers/message.handler.js&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;sockets&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;./store.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;initWebSocketServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpServer&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;wss&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;WebSocketServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection&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;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&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="nx"&gt;IncomingMessage&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;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;console&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="c1"&gt;// 1. Authenticate immediately using the parsed cookie&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;extractUserId&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="c1"&gt;// 2. Reject unauthenticated connections at the handshake level&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Connection is fully authenticated!&lt;/span&gt;
    &lt;span class="c1"&gt;// We can safely associate this socket with the user&lt;/span&gt;
    &lt;span class="nx"&gt;sockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addUser&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="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Proceed with authorized application logic...&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="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; connected successfully.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&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;data&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;// ... handle incoming messages knowing the sender's true identity&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeUserSocket&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="nx"&gt;ws&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;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;When building real-time applications, relying on HTTP-only cookies for authentication eliminates the friction of securing WebSockets. By leaning on the browser's native cookie management, we avoid leaking tokens in URLs and bypass the complexity of first-message authentication handshakes. It requires a tiny bit of manual header parsing on the backend, but the resulting client-side simplicity and security posture are well worth the trade-off.&lt;/p&gt;

&lt;p&gt;For those of you who would like to go through the codebase, you can do so here.&lt;br&gt;
I'll be back with more next week. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>I Built a Real-Time Chat App from scratch - Here's What I Learned</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Tue, 26 May 2026 18:03:37 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/i-built-a-real-time-chat-app-from-scratch-heres-what-i-learned-2nhn</link>
      <guid>https://dev.to/nikhilsharma6/i-built-a-real-time-chat-app-from-scratch-heres-what-i-learned-2nhn</guid>
      <description>&lt;p&gt;When dealing with WebSockets, most tutorials will straightaway hand you Socket.io and call it a day. You get a working chat app in short period of time but you have no idea what happened.&lt;/p&gt;

&lt;p&gt;I actually wanted to understand what was going on, how WebSockets work, how auth happens, how to deal with cookies when working with WebSockets and so many more tiny things.&lt;br&gt;
So I built Relay. A full stack real-time chat app with raw WebSockets, Express for the backend, React for the frontend and PostgreSQL. &lt;br&gt;
The reason for doing everything manually was that I wanted to &lt;strong&gt;learn&lt;/strong&gt;. I did not want to launch and make a chat app and sell it. I just wanted to learn the implementation of these technologies.&lt;/p&gt;

&lt;p&gt;Thus, here we are. This is the first post in a series where I will be exploring the project and breaking down the most interesting technical problems I ran into. But first, let's see what Relay is, how it works, and why I built it the way I did.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Relay Does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time messaging&lt;/strong&gt; — Messages are sent and received instantly over WebSockets. No polling, no long-polling, no hacks. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent history&lt;/strong&gt; — Every message is stored in PostgreSQL via Prisma ORM. Close the tab, logout, the messages will still be there when you come back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie-based auth&lt;/strong&gt; — JWT tokens stored in httpOnly cookies. The WebSocket handshake authenticates by manually parsing cookies from the upgrade request headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual-protocol architecture&lt;/strong&gt; — REST API(the express part) handles the CRUD stuff (auth, fetching users, loading message history). WebSockets handle the real-time stuff (sending messages, live delivery). Each protocol does what it's good at and that is exactly what I wanted to learn to do myself. And also the fact that how would I implement both these protocols in the same project for maximum efficiency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture and Flow
&lt;/h2&gt;

&lt;p&gt;The app follows a fairly standard real-time chat architecture with a clear separation between frontend and backend responsibilities.&lt;/p&gt;

&lt;p&gt;On the frontend, the application is built using React, TypeScript, and Vite. Authentication state is managed through an AuthContext, chat history is handled using a useMessages hook, and real-time communication is managed by a useWebSocket hook. The frontend communicates with the backend in two ways:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REST API&lt;/strong&gt; calls using &lt;strong&gt;Axios&lt;/strong&gt; over HTTP for things like authentication, fetching users, loading messages, and logout.&lt;br&gt;
&lt;strong&gt;WebSocket connections&lt;/strong&gt; (ws://) for real-time messaging and live updates.&lt;/p&gt;

&lt;p&gt;On the backend, the application uses Node.js with Express for REST APIs and the ws library for WebSocket support. The backend exposes REST routes such as /signup, /signin, /users, /messages, /me, and /logout. Alongside this, a WebSocket server handles persistent connections, live message delivery, and connection management.&lt;/p&gt;

&lt;p&gt;Both the REST API layer and WebSocket server interact with the database through Prisma ORM, which connects to a PostgreSQL database for storing users, messages, authentication data, and related application state.&lt;/p&gt;

&lt;p&gt;Now for &lt;strong&gt;the flow&lt;/strong&gt;. This is the part I find most interesting. Here's what happens when you hit send:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt; calls &lt;code&gt;sendMessage(to, content)&lt;/code&gt; which writes a JSON frame to the open WebSocket: &lt;code&gt;{ type: "send_message", payload: { to, content } }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend WS handler&lt;/strong&gt; receives it, validates the payload, and does two things simultaneously:

&lt;ul&gt;
&lt;li&gt;Persists the message to PostgreSQL via Prisma&lt;/li&gt;
&lt;li&gt;Looks up the recipient's socket in the in-memory connection store (which I will update to be a singleton SocketManager class instead of just a map)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If the recipient is online, the backend &lt;strong&gt;pushes&lt;/strong&gt; the message to their socket as a &lt;code&gt;receive_message&lt;/code&gt; event, they see it instantly&lt;/li&gt;
&lt;li&gt;If they're offline, the message is still in the database. Next time they open the chat, the frontend fetches history via the REST endpoint &lt;code&gt;/messages?userId=...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The sender gets an &lt;code&gt;ack&lt;/code&gt; back over the WebSocket confirming the message was processed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No message broker, no queue, no Redis (yet, as that is the plan for v2). Just an in-memory &lt;code&gt;Map&amp;lt;userId, WebSocket&amp;gt;&lt;/code&gt; and a database. It's simple, it works for a single server, and it's the kind of thing that makes you appreciate what a system like Kafka(v2.5 maybe?) is actually solving when you eventually need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here are the interesting bits
&lt;/h2&gt;

&lt;p&gt;All of these will be individual posts in the coming days.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cookie auth over WebSockets
&lt;/h3&gt;

&lt;p&gt;Auth over REST is easy, but how does it happen when dealing with persistent connections. WebSockets don't have a middleware chain and also have no authorization header during the upgrade handshake.&lt;br&gt;
The solution - &lt;strong&gt;cookies!&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The React Stale Closure bug
&lt;/h3&gt;

&lt;p&gt;Imagine opening a chat in two tabs, you receive a message from User A, but see it silently render in the chat window for User B. No backend errors, just a complete UI mismatch.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The dual protocol magic
&lt;/h3&gt;

&lt;p&gt;How the HTTP and WS protocols interleave.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Raw WS
&lt;/h3&gt;

&lt;p&gt;How you create every feature you need using raw WebSockets instead of  Socket.io and have so much more understanding of the concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;For those of you who would like to go through the codebase, you can do so &lt;a href="https://github.com/nikshrma/relay" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
I'll be back with more next week. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>I Built a Real-Time Chat App from scratch - Here's What I Learned</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Tue, 26 May 2026 18:03:37 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/i-built-a-real-time-chat-app-from-scratch-heres-what-i-learned-30dd</link>
      <guid>https://dev.to/nikhilsharma6/i-built-a-real-time-chat-app-from-scratch-heres-what-i-learned-30dd</guid>
      <description>&lt;p&gt;When dealing with WebSockets, most tutorials will straightaway hand you Socket.io and call it a day. You get a working chat app in short period of time but you have no idea what happened.&lt;/p&gt;

&lt;p&gt;I actually wanted to understand what was going on, how WebSockets work, how auth happens, how to deal with cookies when working with WebSockets and so many more tiny things.&lt;br&gt;
So I built Relay. A full stack real-time chat app with raw WebSockets, Express for the backend, React for the frontend and PostgreSQL. &lt;br&gt;
The reason for doing everything manually was that I wanted to &lt;strong&gt;learn&lt;/strong&gt;. I did not want to launch and make a chat app and sell it. I just wanted to learn the implementation of these technologies.&lt;/p&gt;

&lt;p&gt;Thus, here we are. This is the first post in a series where I will be exploring the project and breaking down the most interesting technical problems I ran into. But first, let's see what Relay is, how it works, and why I built it the way I did.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Relay Does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time messaging&lt;/strong&gt; — Messages are sent and received instantly over WebSockets. No polling, no long-polling, no hacks. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent history&lt;/strong&gt; — Every message is stored in PostgreSQL via Prisma ORM. Close the tab, logout, the messages will still be there when you come back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie-based auth&lt;/strong&gt; — JWT tokens stored in httpOnly cookies. The WebSocket handshake authenticates by manually parsing cookies from the upgrade request headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual-protocol architecture&lt;/strong&gt; — REST API(the express part) handles the CRUD stuff (auth, fetching users, loading message history). WebSockets handle the real-time stuff (sending messages, live delivery). Each protocol does what it's good at and that is exactly what I wanted to learn to do myself. And also the fact that how would I implement both these protocols in the same project for maximum efficiency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture and Flow
&lt;/h2&gt;

&lt;p&gt;The app follows a fairly standard real-time chat architecture with a clear separation between frontend and backend responsibilities.&lt;/p&gt;

&lt;p&gt;On the frontend, the application is built using React, TypeScript, and Vite. Authentication state is managed through an AuthContext, chat history is handled using a useMessages hook, and real-time communication is managed by a useWebSocket hook. The frontend communicates with the backend in two ways:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REST API&lt;/strong&gt; calls using &lt;strong&gt;Axios&lt;/strong&gt; over HTTP for things like authentication, fetching users, loading messages, and logout.&lt;br&gt;
&lt;strong&gt;WebSocket connections&lt;/strong&gt; (ws://) for real-time messaging and live updates.&lt;/p&gt;

&lt;p&gt;On the backend, the application uses Node.js with Express for REST APIs and the ws library for WebSocket support. The backend exposes REST routes such as /signup, /signin, /users, /messages, /me, and /logout. Alongside this, a WebSocket server handles persistent connections, live message delivery, and connection management.&lt;/p&gt;

&lt;p&gt;Both the REST API layer and WebSocket server interact with the database through Prisma ORM, which connects to a PostgreSQL database for storing users, messages, authentication data, and related application state.&lt;/p&gt;

&lt;p&gt;Now for &lt;strong&gt;the flow&lt;/strong&gt;. This is the part I find most interesting. Here's what happens when you hit send:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt; calls &lt;code&gt;sendMessage(to, content)&lt;/code&gt; which writes a JSON frame to the open WebSocket: &lt;code&gt;{ type: "send_message", payload: { to, content } }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend WS handler&lt;/strong&gt; receives it, validates the payload, and does two things simultaneously:

&lt;ul&gt;
&lt;li&gt;Persists the message to PostgreSQL via Prisma&lt;/li&gt;
&lt;li&gt;Looks up the recipient's socket in the in-memory connection store (which I will update to be a singleton SocketManager class instead of just a map)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If the recipient is online, the backend &lt;strong&gt;pushes&lt;/strong&gt; the message to their socket as a &lt;code&gt;receive_message&lt;/code&gt; event, they see it instantly&lt;/li&gt;
&lt;li&gt;If they're offline, the message is still in the database. Next time they open the chat, the frontend fetches history via the REST endpoint &lt;code&gt;/messages?userId=...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The sender gets an &lt;code&gt;ack&lt;/code&gt; back over the WebSocket confirming the message was processed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No message broker, no queue, no Redis (yet, as that is the plan for v2). Just an in-memory &lt;code&gt;Map&amp;lt;userId, WebSocket&amp;gt;&lt;/code&gt; and a database. It's simple, it works for a single server, and it's the kind of thing that makes you appreciate what a system like Kafka(v2.5 maybe?) is actually solving when you eventually need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here are the interesting bits
&lt;/h2&gt;

&lt;p&gt;All of these will be individual posts in the coming days.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cookie auth over WebSockets
&lt;/h3&gt;

&lt;p&gt;Auth over REST is easy, but how does it happen when dealing with persistent connections. WebSockets don't have a middleware chain and also have no authorization header during the upgrade handshake.&lt;br&gt;
The solution - &lt;strong&gt;cookies!&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The React Stale Closure bug
&lt;/h3&gt;

&lt;p&gt;Imagine opening a chat in two tabs, you receive a message from User A, but see it silently render in the chat window for User B. No backend errors, just a complete UI mismatch.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The dual protocol magic
&lt;/h3&gt;

&lt;p&gt;How the HTTP and WS protocols interleave.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Raw WS
&lt;/h3&gt;

&lt;p&gt;How you create every feature you need using raw WebSockets instead of  Socket.io and have so much more understanding of the concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;For those of you who would like to go through the codebase, you can do so &lt;a href="https://github.com/nikshrma/relay" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
I'll be back with more next week. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>Week 12: Typescript Magic!</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Sun, 01 Feb 2026 17:11:40 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/week-11-typescript-magic-nmk</link>
      <guid>https://dev.to/nikhilsharma6/week-11-typescript-magic-nmk</guid>
      <description>&lt;p&gt;Last week, we talked about how Prisma helps us in simplifying our DB queries, but as a project grows, we face another massive challenge: &lt;strong&gt;consistency&lt;/strong&gt;. When you have dozens of files and data moving between them, it's very easy to lose track of what "shape" an object has. &lt;/p&gt;

&lt;p&gt;In plain JavaScript, you might call a property user_id in your database logic, userId in your controller, and just id in your frontend. In a small project, you can keep that in your head. In a production-level app? &lt;/p&gt;

&lt;p&gt;It’s a straight-up disaster waiting to happen. You won't know something is broken until the code actually runs and crashes with the dreaded Cannot read property 'id' of undefined. &lt;/p&gt;

&lt;p&gt;The solution is &lt;strong&gt;TypeScript&lt;/strong&gt;. It’s not just "JavaScript with types"; it’s a high-tech safety net. It creates a development environment where the editor itself understands your data structures. It ensures that if you change a property name in one place, the rest of your app doesn't quietly crumble—it screams at you until you fix it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1a. Setting Up the Environment📎
&lt;/h3&gt;

&lt;p&gt;Unlike JavaScript, which Node.js or a browser can read directly, TypeScript needs to be "transpiled." Think of it as a pre-processing step where your type-heavy TS code is stripped down into clean, performant JS that engines can actually execute. To get started, the setup involves a few key commands that I now have on muscle memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Initialize a node project to manage dependencies&lt;/span&gt;
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Install TypeScript as a dev dependency (we don't need it in production)&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;typescript &lt;span class="nt"&gt;--save-dev&lt;/span&gt;

&lt;span class="c"&gt;# Initialize the TypeScript compiler and create the config&lt;/span&gt;
npx tsc &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a tsconfig.json file. This file is the "brain" of your project. It’s where you tell the compiler exactly how strict you want to be, which version of JavaScript to target, and where to look for your files. &lt;/p&gt;

&lt;h3&gt;
  
  
  1b. Organizing with rootDir and outDir
&lt;/h3&gt;

&lt;p&gt;In a professional workflow, you never want your source code (the stuff you edit) and the distribution code (the stuff that runs) mixed together. It makes version control a nightmare and the project structure confusing. &lt;/p&gt;

&lt;p&gt;To solve this, we dive into the tsconfig.json and configure two crucial settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;rootDir:&lt;/strong&gt; This points the compiler to our source folder. Usually, we set this to ./src. This is where all our .ts files live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;outDir:&lt;/strong&gt; This tells the compiler where to dump the generated JavaScript. We usually use ./dist (distribution) or ./build. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By setting these up, your workflow becomes streamlined: you write code in src, run npx tsc, and TypeScript replicates your entire folder structure inside dist, but converted to JavaScript. This keeps your project clean and ready for deployment. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Beyond Basics: Interfaces, Enums, and Generics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A. The Power of Interfaces
&lt;/h3&gt;

&lt;p&gt;Interfaces enforce a "contract." If a blueprint says a house needs four windows, TypeScript won't let you build it with three.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Using an Enum&lt;/span&gt;
    &lt;span class="nl"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// Optional property&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  B. Enums: Eliminating "Magic Strings"
&lt;/h3&gt;

&lt;p&gt;Don't use strings like &lt;code&gt;"admin"&lt;/code&gt; or &lt;code&gt;"guest"&lt;/code&gt; throughout your code. Use &lt;strong&gt;Enums&lt;/strong&gt; to create a single source of truth for constant values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;UserRole&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ADMIN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Moderator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MODERATOR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USER&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;myUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nikhil_Dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nikhil@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Admin&lt;/span&gt; &lt;span class="c1"&gt;// Type-safe and discoverable&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  C. Generics: Writing Reusable Logic
&lt;/h3&gt;

&lt;p&gt;Generics allow you to create components that work over a variety of types rather than a single one. This is crucial for API responses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ApiResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Now we can reuse this for Users, Products, or Orders&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myUser&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. End-to-End Type Safety (Frontend + Backend)
&lt;/h2&gt;

&lt;p&gt;The "Holy Grail" of development is sharing types across your stack. By exporting interfaces from a shared folder, your Frontend knows exactly what the Backend is sending.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared Function Signatures
&lt;/h3&gt;

&lt;p&gt;Imagine a function that updates a user profile. In TypeScript, we can ensure the payload matches the expected structure before the API call is even made.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UpdateUserPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUser&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UpdateUserPayload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;// TypeScript ensures payload only contains username or tags&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/user/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  New things I learnt this week🔄
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Power of strict: true:&lt;/strong&gt; Turning this on in tsconfig is like playing a game on "Hard Mode." It forces you to handle null and undefined cases explicitly. It’s annoying at first, but it eliminates about 90% of common runtime bugs. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeting Environments:&lt;/strong&gt; I learned that I can write modern ES6+ TypeScript but tell the compiler to output older ES5 code if I need to support legacy environments. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Inference:&lt;/strong&gt; I realized I don't have to define everything. If I write let name = "Nikhil", TypeScript is smart enough to know it's a string. You only need to be explicit when things get complex.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;While the topics that I covered this week were small, they are crucial and of immense importance when building production-ready apps. If you have any questions or feedback, make sure to comment and let me know! &lt;/p&gt;

&lt;p&gt;I'll be back next week with more. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Week 11: Prisma!</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Wed, 17 Dec 2025 04:57:00 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/week-11-prisma-3lpo</link>
      <guid>https://dev.to/nikhilsharma6/week-11-prisma-3lpo</guid>
      <description>&lt;p&gt;This week I explored the &lt;strong&gt;Prisma ORM&lt;/strong&gt;, which simplifies our SQL journey by a LOT. Let’s get right into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered✅
&lt;/h2&gt;

&lt;p&gt;Last week, I worked with basic schemas and simple database interactions. But once our data starts to grow and multiple entities are involved, raw SQL queries or loosely typed database access quickly become messy and error-prone.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;Prisma&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;This week revolved around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding what an ORM actually solves&lt;/li&gt;
&lt;li&gt;Defining a database schema using Prisma&lt;/li&gt;
&lt;li&gt;Generating type-safe database clients&lt;/li&gt;
&lt;li&gt;Performing CRUD operations cleanly and safely&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. What is Prisma and why do we need it? 🧠
&lt;/h2&gt;

&lt;p&gt;Prisma is an &lt;strong&gt;ORM (Object Relational Mapper)&lt;/strong&gt;. In simple terms, it acts as a bridge between our database and our application code.&lt;/p&gt;

&lt;p&gt;Without Prisma, we might write raw SQL like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'test@gmail.com'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Prisma, the same thing looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&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;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We don’t manually write SQL for every operation&lt;/li&gt;
&lt;li&gt;Queries become &lt;strong&gt;type-safe&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Refactoring database fields doesn’t silently break things&lt;/li&gt;
&lt;li&gt;Autocomplete + compile-time checks save us from runtime bugs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Prisma Schema — the single source of truth 📄
&lt;/h2&gt;

&lt;p&gt;First we initialise Prisma in our project (for which you can refer to the &lt;a href="https://www.prisma.io/docs" rel="noopener noreferrer"&gt;docs here&lt;/a&gt;).&lt;br&gt;
At the heart of all generated files lies the &lt;code&gt;schema.prisma&lt;/code&gt; file. This file defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;our database connection&lt;/li&gt;
&lt;li&gt;our models (tables)&lt;/li&gt;
&lt;li&gt;relationships between models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A basic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This schema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a &lt;code&gt;User&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;Automatically enforces uniqueness on email&lt;/li&gt;
&lt;li&gt;Generates types that our editor understands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once this is written, running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;creates a fully typed Prisma Client for us — which we can just import in our DB setup files and use as simply as this -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaPg&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/adapter-pg&lt;/span&gt;&lt;span class="dl"&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;PrismaClient&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;@/app/generated/prisma/client&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;adapter&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;PrismaPg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&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;prisma&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;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;adapter&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;
  
  
  3. Migrations — evolving the database safely 🔁
&lt;/h2&gt;

&lt;p&gt;Databases are never static. Fields get added, removed, or changed. Prisma handles this through &lt;strong&gt;migrations&lt;/strong&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma migrate dev &lt;span class="nt"&gt;--name&lt;/span&gt; add-user-model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a migration file&lt;/li&gt;
&lt;li&gt;Applies changes to the database&lt;/li&gt;
&lt;li&gt;Keeps history of schema evolution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures our local DB, staging DB, and production DB all stay in sync. And the generated migration files are simply the SQL versions of the queries that we can write easily using Prisma.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. CRUD operations with Prisma ✍️
&lt;/h2&gt;

&lt;p&gt;Prisma makes CRUD operations intuitive and readable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nikhil@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nikhil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Read
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&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;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Updated Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Delete
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these operations is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typed&lt;/li&gt;
&lt;li&gt;Validated at compile time&lt;/li&gt;
&lt;li&gt;Predictable in behaviour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And to see what parameters these functions expect we can just refer to the docs. &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Relations and foreign keys made simple 🔗
&lt;/h2&gt;

&lt;p&gt;Defining relations in Prisma is surprisingly clean.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id     Int  @id @default(autoincrement())
  title  String
  user   User @relation(fields: [userId], references: [id])
  userId Int
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Prisma understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One user → many posts&lt;/li&gt;
&lt;li&gt;How to join data internally&lt;/li&gt;
&lt;li&gt;How to fetch nested data safely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fetching related data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&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;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;posts&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  New things I learnt this week 🔄
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prisma acts as an intermediary between our code and database - increasing our ease while also giving type safety, which is an absolute game changer.&lt;/li&gt;
&lt;li&gt;Schema-first design prevents an entire class of bugs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;While Prisma might feel like “just another tool”, it fundamentally changes how confidently we interact with our database. Clean schemas and safe migrations make production systems far more reliable. &lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, make sure to comment and let me know! &lt;strong&gt;Also, if you have any project ideas for me, please drop em in the comments!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ll be back next week with more. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Week 10: Databases - The Real Backbone of Our Apps!</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Mon, 08 Dec 2025 18:14:30 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/week-10-databases-the-real-backbone-of-our-apps-2k45</link>
      <guid>https://dev.to/nikhilsharma6/week-10-databases-the-real-backbone-of-our-apps-2k45</guid>
      <description>&lt;p&gt;This week, I went deeper into something that quietly run the entire show behind our apps - &lt;strong&gt;databases&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Honestly, this was one of those weeks where everything just &lt;em&gt;clicked&lt;/em&gt;. The more I understood, the more things felt structured and “ohhh, so that's how it's done.” Let’s get right into it!&lt;/p&gt;


&lt;h2&gt;
  
  
  🗂️ Types of Databases
&lt;/h2&gt;

&lt;p&gt;At the highest level, we can split databases into two big families:&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. SQL Databases (Relational)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These are structured, rigid, strict but all in a good way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data lives in &lt;strong&gt;tables&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Tables have &lt;strong&gt;columns&lt;/strong&gt; with fixed types
&lt;/li&gt;
&lt;li&gt;There are &lt;strong&gt;relationships&lt;/strong&gt; between tables
&lt;/li&gt;
&lt;li&gt;Everything is based on a schema we define upfront
&lt;/li&gt;
&lt;li&gt;We interact using &lt;strong&gt;SQL (Structured Query Language)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples: &lt;strong&gt;PostgreSQL, MySQL, MariaDB, SQL Server&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;2. NoSQL Databases (Non-Relational)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These are way more flexible and relaxed with structure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No fixed schema
&lt;/li&gt;
&lt;li&gt;Great for rapidly changing data
&lt;/li&gt;
&lt;li&gt;Designed for quick reads, massive scale
&lt;/li&gt;
&lt;li&gt;Data can be documents, key-value pairs, graphs, columns…
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples: &lt;strong&gt;MongoDB, Redis, Cassandra, DynamoDB&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Where MongoDB Fits
&lt;/h2&gt;

&lt;p&gt;MongoDB is a &lt;strong&gt;NoSQL Document Database&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Instead of rows and columns, MongoDB stores data as &lt;strong&gt;documents&lt;/strong&gt; that look like JSON.&lt;/p&gt;

&lt;p&gt;A user record might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ayu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hobbies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"painting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reading"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is super flexible! We can add or remove fields anytime and get no schema alerts.&lt;/p&gt;




&lt;h2&gt;
  
  
  MongoDB Advantages
&lt;/h2&gt;

&lt;p&gt;MongoDB does a bunch of things &lt;em&gt;really&lt;/em&gt; well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema flexibility&lt;/strong&gt; - perfect for fast prototyping
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal scaling&lt;/strong&gt; - adding more servers is easier
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Great for document-shaped data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works naturally with JavaScript&lt;/strong&gt; since it uses JSON-like syntax
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High read performance&lt;/strong&gt; when queries align with document structure
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we want speed and flexibility(say in a hackathon), MongoDB feels amazing.&lt;/p&gt;




&lt;h2&gt;
  
  
  But MongoDB Has Its Downsides Too
&lt;/h2&gt;

&lt;p&gt;As we scale, we start to notice some cracks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Relationships are painful&lt;/strong&gt;
Joining data across collections feels messy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data integrity isn’t guaranteed by default&lt;/strong&gt;
If we expect strict correctness → things get tricky.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query patterns can degrade performance&lt;/strong&gt;
Indexing becomes super important and manually tuned.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Harder to enforce structure&lt;/strong&gt;
Which means bugs can slip into the data layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MongoDB is perfect until we need the kind of discipline that big systems demand.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Why Most Companies Still Prefer SQL
&lt;/h2&gt;

&lt;p&gt;Across the industry, SQL remains the default, and once we dig into it, the reasons feel obvious.&lt;/p&gt;

&lt;p&gt;SQL databases like &lt;strong&gt;Postgres&lt;/strong&gt; give us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure
&lt;/li&gt;
&lt;li&gt;Predictability
&lt;/li&gt;
&lt;li&gt;Reliability
&lt;/li&gt;
&lt;li&gt;Better Relationships
&lt;/li&gt;
&lt;li&gt;ACID guarantees
&lt;/li&gt;
&lt;li&gt;Rich querying capabilities
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When correctness matters, SQL usually wins.&lt;br&gt;&lt;br&gt;
Say in payments, inventory, authentication, banking, analytics, logistics and so many more. Basically anything where one mistake can cause a lot of trouble, SQL wins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why SQL (especially Postgres) feels better for many use cases:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every table has a schema → fewer “surprise bugs”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong JOIN support&lt;/strong&gt; → complex relationships are easy
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions&lt;/strong&gt; → either everything succeeds or nothing does
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indices, constraints, triggers&lt;/strong&gt; → very mature tooling
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postgres-specific power-ups:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;JSON support (best of both worlds)
&lt;/li&gt;
&lt;li&gt;Window functions
&lt;/li&gt;
&lt;li&gt;Full-text search
&lt;/li&gt;
&lt;li&gt;Extensions like &lt;code&gt;pgvector&lt;/code&gt;, &lt;code&gt;PostGIS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Postgres feels like that reliable friend who just never drops the ball.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ But SQL Has Some Cons Too
&lt;/h2&gt;

&lt;p&gt;Nothing is perfect.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Schema changes can be heavy
&lt;/li&gt;
&lt;li&gt;Horizontal scaling is harder
&lt;/li&gt;
&lt;li&gt;Rigid structure might feel slow during rapid iteration
&lt;/li&gt;
&lt;li&gt;Requires more planning upfront
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still, for most of the systems we want to build, SQL’s strengths massively outweigh its weaknesses.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐘 Our Choice This Week: &lt;strong&gt;PostgreSQL&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So this week was all about &lt;strong&gt;Postgres&lt;/strong&gt;, one of the most powerful SQL databases out there.&lt;/p&gt;

&lt;p&gt;We focused on understanding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How tables are created
&lt;/li&gt;
&lt;li&gt;How constraints keep our data safe
&lt;/li&gt;
&lt;li&gt;How relationships work using foreign keys
&lt;/li&gt;
&lt;li&gt;How SQL queries are structured
&lt;/li&gt;
&lt;li&gt;Why good database design matters
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And since we’re building in the JavaScript ecosystem, we’ll be pairing Postgres with &lt;strong&gt;Prisma&lt;/strong&gt; as our ORM but that’s a whole topic by itself, so that’s coming next week.&lt;/p&gt;

&lt;p&gt;This week is pure SQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  SQL Examples — With Intuition
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ▶ Creating a Table
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What’s happening?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We’re designing a structure where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; auto-increments
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; must always exist
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;email&lt;/code&gt; must be unique
&lt;/li&gt;
&lt;li&gt;Postgres will now enforce these rules for us
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the kind of discipline that NoSQL doesn’t enforce.&lt;/p&gt;




&lt;h3&gt;
  
  
  ▶ Inserting Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Ayu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ayu@example.com'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This just means:&lt;br&gt;&lt;br&gt;
“Put a new row into the &lt;code&gt;users&lt;/code&gt; table with these values.”&lt;/p&gt;

&lt;p&gt;SQL has a learning curve which could be slow in the beginning but, as is the case with everything, gets easier with practice.&lt;/p&gt;




&lt;h3&gt;
  
  
  ▶ Querying Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ayu@example.com'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re pulling only the data that matters.&lt;br&gt;&lt;br&gt;
This precision is where SQL shines.&lt;/p&gt;




&lt;h3&gt;
  
  
  ▶ Updating Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Ayu'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re telling Postgres:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Find the row where &lt;code&gt;id = 1&lt;/code&gt;”&lt;/li&gt;
&lt;li&gt;“Change the name to Ayu”
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ▶ Deleting Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again - clean and readable(because our use-case is simple – SQL queries can get very complex, but an ORM helps simplify it further).&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;This week gave us a solid foundation in understanding why databases behave the way they do, and why SQL (especially Postgres) is still the king for most real-world applications. MongoDB is incredible for flexibility and fast-moving projects but SQL is unbeatable for consistency and correctness.&lt;/p&gt;

&lt;p&gt;Next week, we’ll take all this knowledge and plug it into &lt;strong&gt;Prisma&lt;/strong&gt;, making database interactions feel a LOT easier.&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, make sure to comment and let me know!&lt;/p&gt;

&lt;p&gt;I'll be back next week with more. Until then, stay consistent!  &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>postgres</category>
      <category>beginners</category>
      <category>backend</category>
    </item>
    <item>
      <title>Week 9: Using Recoil in React!</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Mon, 01 Dec 2025 18:28:41 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/week-9-using-recoil-in-react-2m0j</link>
      <guid>https://dev.to/nikhilsharma6/week-9-using-recoil-in-react-2m0j</guid>
      <description>&lt;p&gt;Back after 2 weeks of vacation!(it was actually a continuous battle with so many evaluations and exams at college). During this time I've been covering State Management with context API and Recoil! Let's get right into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered✅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Context API&lt;/li&gt;
&lt;li&gt;Problems with Context API&lt;/li&gt;
&lt;li&gt;Recoil and why it's better&lt;/li&gt;
&lt;li&gt;Atoms &amp;amp; Selectors&lt;/li&gt;
&lt;li&gt;Recoil hooks (&lt;code&gt;useRecoilState&lt;/code&gt;, &lt;code&gt;useRecoilValue&lt;/code&gt;, &lt;code&gt;useSetRecoilState&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;RecoilRoot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When to still use &lt;code&gt;useState&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  1. Starting with the Context API 🧩
&lt;/h1&gt;

&lt;p&gt;Last week, we spoke about prop drilling and how passing props through multiple layers can make your code look messy. The &lt;strong&gt;Context API&lt;/strong&gt; is React’s built-in solution to this.&lt;/p&gt;

&lt;p&gt;It lets you create &lt;strong&gt;global-ish&lt;/strong&gt; state without prop drilling.&lt;/p&gt;

&lt;p&gt;Here’s a tiny example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UserContext.jsx&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;createContext&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;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// App.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserContext&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;./UserContext&lt;/span&gt;&lt;span class="dl"&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;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nikhil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Parent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Child.jsx&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;useContext&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;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserContext&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;./UserContext&lt;/span&gt;&lt;span class="dl"&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;Child&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This appears to work well. But it does so only for small and simple apps.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. The problem? 😵‍💫
&lt;/h1&gt;

&lt;p&gt;As our app grows, Context API introduces a few issues:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Re-renders
&lt;/h2&gt;

&lt;p&gt;Any value change in the context re-renders every component that consumes it, even if only one component actually needed the update.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Too many contexts
&lt;/h2&gt;

&lt;p&gt;You often end up creating multiple contexts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserContext&lt;/li&gt;
&lt;li&gt;ThemeContext&lt;/li&gt;
&lt;li&gt;NotificationContext&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and so on.&lt;/p&gt;

&lt;p&gt;This becomes hard to organise and maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Not a full state management solution
&lt;/h2&gt;

&lt;p&gt;Context wasn't designed for big, complex global state. It's more of a “prop drilling escape hatch”.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Recoil ⚛️ - The solution
&lt;/h1&gt;

&lt;p&gt;Recoil is a super-lightweight state management library made for React. It fixes the problems above without introducing the complexity of Redux.&lt;/p&gt;

&lt;p&gt;Why Recoil feels so good:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It updates only the components that need the state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You don’t need multiple providers — everything sits under one RecoilRoot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It’s extremely intuitive because it feels like working with React’s useState.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Recoil introduces atoms, which are simply pieces of global state.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  4. Getting started with Recoil
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 1: Wrap your app in a RecoilRoot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&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;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&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;./App&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;RecoilRoot&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;recoil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RecoilRoot&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RecoilRoot&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2:Creating an atom
&lt;/h2&gt;

&lt;p&gt;Atoms store global state. We usually create them in a separate folder and export them from there and then we can use them globally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// atoms/userAtom.jsx&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;atom&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;recoil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userAtom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userAtom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nikhil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3:Using the globally declared states in Components
&lt;/h2&gt;

&lt;p&gt;For this we use majorly three functions&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;useRecoilState → like useState but global
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRecoilState&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;recoil&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;userAtom&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;./atoms/userAtom&lt;/span&gt;&lt;span class="dl"&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;UserUpdater&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRecoilState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAtom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ayu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Change User
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;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;ol&gt;
&lt;li&gt;useRecoilValue → read-only access- so it basically just gives us the variable and not the function to change its value.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRecoilValue&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;recoil&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;userAtom&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;./atoms/userAtom&lt;/span&gt;&lt;span class="dl"&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;UserDisplay&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRecoilValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAtom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;useSetRecoilState → write-only access
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSetRecoilState&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;recoil&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;userAtom&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;./atoms/userAtom&lt;/span&gt;&lt;span class="dl"&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;LogoutButton&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;setUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSetRecoilState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAtom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Logout&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Selectors -
&lt;/h3&gt;

&lt;p&gt;Selectors let you derive data from atoms, say computed values. This is how we'd create one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;selector&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;recoil&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;userAtom&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;./userAtom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;capitalisedUserSelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;capitalisedUserSelector&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="kd"&gt;get&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAtom&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="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;And to use it we do this-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRecoilValue&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;recoil&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;capitalisedUserSelector&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;./atoms/selectors&lt;/span&gt;&lt;span class="dl"&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;Display&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRecoilValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;capitalisedUserSelector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  5. Should we ditch useState now?
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Not at all.&lt;/strong&gt;&lt;br&gt;
If a state variable is only needed by 1–2 components, using Recoil is unnecessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No reason to make count global here. React’s local state is still perfect for component-specific logic.&lt;br&gt;
We use Recoil only when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many components need the same state&lt;/li&gt;
&lt;li&gt;Passing props becomes painful&lt;/li&gt;
&lt;li&gt;Context starts slowing down your UI
## Things I found interesting this week&lt;/li&gt;
&lt;li&gt;Seeing how Recoil prevents unnecessary re-renders felt magical. The component isolation makes the app feel snappier.&lt;/li&gt;
&lt;li&gt;Atoms being global state and also visually being "global state" made the learning curve super smooth for me.
## Wrapping up🔄
Interesting week.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While learning Recoil this week, I actually didn’t know that the library had been archived. Since I had already started, I went ahead and completed it anyway — the concepts are super useful to understand. I’ll be moving to Jotai soon since it’s lightweight, actively maintained, and follows a similar mental model to Recoil, so the transition should feel smooth. &lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, make sure to comment and let me know!&lt;/p&gt;

&lt;p&gt;I'll be back next week with more. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>Vacation week!</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Mon, 17 Nov 2025 16:39:25 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/vacation-week-2489</link>
      <guid>https://dev.to/nikhilsharma6/vacation-week-2489</guid>
      <description>&lt;p&gt;This week wasn’t about new concepts or heavy learning.&lt;br&gt;
Exams are around the corner, I’ve been traveling back and forth between home and college, and it was also the birthday of someone very close to me. So life was a little full in the best ways.&lt;/p&gt;

&lt;p&gt;So this became a vacation week. A breather I honestly needed.&lt;/p&gt;

&lt;p&gt;I'll be back with more next week! Till then, stay consistent.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Week 8: Routing, Lazy Loading and more in React!🎨</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Mon, 10 Nov 2025 18:00:04 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/week-8-routing-lazy-loading-and-more-in-react-466l</link>
      <guid>https://dev.to/nikhilsharma6/week-8-routing-lazy-loading-and-more-in-react-466l</guid>
      <description>&lt;p&gt;This week I delved into an absolute essential for building a web application! Client-side routing and lazy loading. Let's get right into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered✅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Client-side routing&lt;/li&gt;
&lt;li&gt;Lazy-loading&lt;/li&gt;
&lt;li&gt;Prop-drilling and its solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Routing📎
&lt;/h3&gt;

&lt;p&gt;Routing is one of the first things that I'd do if I was in a hackathon and needed to get a project up and running quickly. &lt;/p&gt;

&lt;p&gt;React enables us to build single-page applications (SPAs), where navigating between pages doesn’t trigger a &lt;strong&gt;full page reload.&lt;/strong&gt; Instead of reloading the entire site and fetching a new HTML file each time, React uses &lt;strong&gt;client-side routing&lt;/strong&gt;. This means the app dynamically updates the content and changes the URL without requesting a new page from the server. &lt;/p&gt;

&lt;p&gt;This approach makes navigation &lt;strong&gt;faster and smoother&lt;/strong&gt;, since the JavaScript bundle is loaded only once, and React handles rendering the appropriate components for each route.&lt;/p&gt;

&lt;p&gt;This is how we'd change the route in a very superficial way&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";

function Home() {
  const goToAbout = () =&amp;gt; {
    // This causes a full page reload instead of client-side routing
    window.location.href = "/about";
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Welcome to Home Page&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={goToAbout}&amp;gt;Go to About&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default Home;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you'll notice that here too , the page hard reloads. To avoid this, we use a library that helps in routing — 'react-router-dom'. Here is how we'd use that to do the same routing as above&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { useNavigate } from "react-router-dom";

function Home() {
  const navigate = useNavigate();

  const goToAbout = () =&amp;gt; {
    // This changes route without reloading the page
    navigate("/about");
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Welcome to Home Page&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={goToAbout}&amp;gt;Go to About&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
export default Home;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there's a little caveat that comes with the &lt;strong&gt;useNavigate()&lt;/strong&gt;hook we use here. It can only be used &lt;strong&gt;inside components that are wrapped by a Router&lt;/strong&gt;. This means that for the useNavigate hook to work, the component must be rendered within a Router context provided by react-router-dom.&lt;br&gt;
This is how our &lt;strong&gt;App() function&lt;/strong&gt; should look for the above to work-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./Home";
import About from "./About";

function App() {
  return (
    //  useNavigate works only inside components wrapped by a Router
    &amp;lt;BrowserRouter&amp;gt;
      &amp;lt;Routes&amp;gt;
        &amp;lt;Route path="/" element={&amp;lt;Home /&amp;gt;} /&amp;gt;
        &amp;lt;Route path="/about" element={&amp;lt;About /&amp;gt;} /&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/BrowserRouter&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This stops the page from hard reloading and instead does client-side routing! This is crucial for building fast web applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lazy loading 💤
&lt;/h3&gt;

&lt;p&gt;Another thing we can do to optimise the user's experience is to add lazy-loading to our application. But that is truly useful only if our application has grown large enough.&lt;/p&gt;

&lt;p&gt;But below is an example of how to do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { Suspense } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";

// Lazy load the About component
const About = React.lazy(() =&amp;gt; import("./About"));
import Home from "./Home";

function App() {
  return (
    &amp;lt;BrowserRouter&amp;gt;
      {/* Suspense shows fallback while About is being loaded */}
      &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
        &amp;lt;Routes&amp;gt;
          &amp;lt;Route path="/" element={&amp;lt;Home /&amp;gt;} /&amp;gt;
          &amp;lt;Route path="/about" element={&amp;lt;About /&amp;gt;} /&amp;gt;
        &amp;lt;/Routes&amp;gt;
      &amp;lt;/Suspense&amp;gt;
    &amp;lt;/BrowserRouter&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice here that we have to use the &lt;strong&gt;Suspense API&lt;/strong&gt; along with lazy loading else React throws us an error. What this API does is that it allows us to add a "fallback" in case the user's network is too slow and the component cannot load in time. &lt;/p&gt;

&lt;p&gt;Another benefit for lazy loading is that it reduces the initial bundle size of our application, leading to faster load times and improved performance, especially for users with slower internet connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Prop Drilling
&lt;/h3&gt;

&lt;p&gt;In one of the earlier blog posts, when we read about various  app optimisation techniques and the need to lower our re-renders we studied how we should push down state to the lowest common ancestors of the &lt;strong&gt;nodes&lt;/strong&gt; that need those state variables. &lt;/p&gt;

&lt;p&gt;But this could still lead to scenarios where the state variable is being passed down through multiple components that don't need the variables for themselves but still have to pass it down. This leads to code that can look very unappealing and overtime become difficult to manage. &lt;/p&gt;

&lt;p&gt;This visually and syntactically bad looking problem is what we call &lt;strong&gt;Prop Drilling&lt;/strong&gt;. &lt;em&gt;Note that prop drilling doesn't have much to do with performance issues as much as it is about the visual and structural complexity it causes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Below is a small example of prop drilling-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";

function App() {
  const user = "Nikhil";
  return &amp;lt;Parent user={user} /&amp;gt;;
}

function Parent({ user }) {
  //Parent doesn't need 'user', but passes it down anyway
  return &amp;lt;Child user={user} /&amp;gt;;
}

function Child({ user }) {
  return &amp;lt;GrandChild user={user} /&amp;gt;;
}

function GrandChild({ user }) {
  return &amp;lt;h2&amp;gt;Hello, {user}!&amp;lt;/h2&amp;gt;;
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observe here how the user prop travels through multiple components (Parent, Child) that don’t actually need it — they just pass it along so GrandChild can use it. &lt;strong&gt;This is prop drilling.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution -
&lt;/h3&gt;

&lt;p&gt;The solution, as we discussed earlier, is to somehow move all of the state logic outside the components, so that they exist globally. That way, any component that needs it can just call it and use it without it being needed to passed down.&lt;/p&gt;

&lt;p&gt;We can do this using two things- &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Context API&lt;/strong&gt; which is built into React but has its limitations like-

&lt;ul&gt;
&lt;li&gt;It can lead to unnecessary re-renders if not used carefully.&lt;/li&gt;
&lt;li&gt;It is not a full-fledged state management solution and may not be suitable for very complex state management needs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;A state management library&lt;/strong&gt; like RTK(redux tool kit), Recoil(now archived) or some lightweight library built on principles of Recoil, like Jotai or Zustand. These libraries provide more robust solutions for managing global state in larger applications.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;We cover both of these topics in the next blog together!&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I found interesting this week
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lazy loading was such a cool concept! Seeing the components load one-by-one in the networks tab was really interesting.&lt;/li&gt;
&lt;li&gt;Client-side-routing really tickled a corner of my brain that I did not know wanted to be tickled. Taught me how the URL change in the search bar when we click on different links on a site.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up🔄
&lt;/h2&gt;

&lt;p&gt;Another week gone and some more fundamentals mastered. Really interested to do a state-management library next week. If you have any questions or feedback, make sure to comment and let me know!&lt;/p&gt;

&lt;p&gt;I'll be back next week with more. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Week 7: React hooks and more!</title>
      <dc:creator>Nikhil Sharma</dc:creator>
      <pubDate>Mon, 03 Nov 2025 18:25:04 +0000</pubDate>
      <link>https://dev.to/nikhilsharma6/week-7-react-hooks-and-more-36g4</link>
      <guid>https://dev.to/nikhilsharma6/week-7-react-hooks-and-more-36g4</guid>
      <description>&lt;p&gt;This week was very light. I did not cover anything that was too new or too hard because I needed a break and also wanted to stay in touch! So let's get right into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics Covered✅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React returns- the need to return just one parent component&lt;/li&gt;
&lt;li&gt;Re-Renders and minimising them&lt;/li&gt;
&lt;li&gt;Keys in React&lt;/li&gt;
&lt;li&gt;Wrapper components and children&lt;/li&gt;
&lt;li&gt;Hooks&lt;/li&gt;
&lt;li&gt;React.memo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get into them in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. React Returns
&lt;/h3&gt;

&lt;p&gt;If you notice that when we try to return sibling components out of a React component, React screams a huge &lt;strong&gt;NO&lt;/strong&gt;. This is because React components must return a single root element. Returning multiple sibling elements isn’t allowed because each component needs one clear root in the virtual DOM tree. This structure enables React’s reconciliation process to work efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Re-Renders and minimising them
&lt;/h3&gt;

&lt;p&gt;A re-render in React happens when a component’s output (its JSX) is recalculated, and React determines whether the DOM needs to be updated or not. Unnecessary or frequent re-renders can impact performance if not managed properly, thus, we need to minimise them.&lt;/p&gt;

&lt;p&gt;If a parent component re-renders then all its child components re-render along with it. One way to optimise re-renders is to push down state into the lowest common ancestor of the nodes(or components) which need the state. We can also use something called React.memo which we will cover later in this blog.&lt;/p&gt;

&lt;p&gt;Realistically, we would do this by pushing all state outside our core logic and &lt;strong&gt;using a state-management tool&lt;/strong&gt; like Recoil(archived), RTK(Redux Toolkit) or something light like Jotai or Zustand.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Keys in React
&lt;/h3&gt;

&lt;p&gt;Whenever we render something in react which is a list of items like we did in our last blog.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function Todos({todos , setTodos}){
    return &amp;lt;div&amp;gt;
        {todos.map((todo)=&amp;gt;{
            return &amp;lt;div key={todo.id}&amp;gt;
               &amp;lt;h1&amp;gt;{todo.title}&amp;lt;/h1&amp;gt;
               &amp;lt;h1&amp;gt;{todo.description}&amp;lt;/h1&amp;gt;
               {todo.completed?&amp;lt;span&amp;gt;Completed&amp;lt;/span&amp;gt;:&amp;lt;button onClick={()=&amp;gt;{
                handleCompleted(todo._id,todos ,setTodos);
               }}&amp;gt;Mark as done&amp;lt;/button&amp;gt;}
                &amp;lt;/div&amp;gt;
        })}
    &amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, React gives a soft warning when in StrictMode which says -&lt;br&gt;
"Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of TodoList. See fb.me/react-warning-keys for more information."&lt;/p&gt;

&lt;p&gt;What this means is that React needs some sort of a key to recognise which item in the list is being manipulated, deleted, moved around or anything of the sorts.&lt;/p&gt;

&lt;p&gt;We can do this by adding a key prop to each todo as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return &amp;lt;div key={todo._id}&amp;gt; // parent div
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Wrapper Components and children
&lt;/h3&gt;

&lt;p&gt;Wrapper components come in handy when we want uniformity across components written by different people working on a project. In such cases, one person can define a &lt;strong&gt;&lt;em&gt;wrapper component&lt;/em&gt;&lt;/strong&gt; that handles common structure, styling, or logic. Other developers can then pass their component content as children to this wrapper.&lt;/p&gt;

&lt;p&gt;An example of this is as follows-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Card({ children }) {
  return &amp;lt;div className="card"&amp;gt;{children}&amp;lt;/div&amp;gt;;
}

// Usage
&amp;lt;Card&amp;gt;
  &amp;lt;h2&amp;gt;Title&amp;lt;/h2&amp;gt;
  &amp;lt;p&amp;gt;This is inside the card!&amp;lt;/p&amp;gt;
&amp;lt;/Card&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. React.memo
&lt;/h3&gt;

&lt;p&gt;React.memo is a higher-order component that helps optimize performance by preventing unnecessary re-renders of functional components.&lt;/p&gt;

&lt;p&gt;When you wrap a component with React.memo, React will only re-render it if its props change. If the props remain the same between renders, React skips rendering that component and reuses the previous result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const TodoItem = React.memo(function TodoItem({ title, description }) {
  console.log("Rendered:", title);
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;{title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{description}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the parent component re-renders but the props (title, description) for a particular TodoItem stay the same, that TodoItem won’t re-render and this saves computation time.&lt;/p&gt;

&lt;p&gt;This is especially useful when you have large lists or expensive UI components that don’t need to update unless their data actually changes. But again this will be handled even better when we use a state-management library.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Hooks
&lt;/h3&gt;

&lt;p&gt;While we did use some hooks like useState and useEffect in last week's project, this was more of an official definition. Hooks are functions that allow us to hook into react state and lifecycle features from functional components. And while there are a lot of hooks, only a handful are used in most code bases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up🔚
&lt;/h2&gt;

&lt;p&gt;While this week was more theoretical and very light, it does set up some paths that will be very interesting in the upcoming weeks. Especially the state-management part is quite interesting. &lt;strong&gt;Some very intriguing stuff coming in the next weeks.&lt;/strong&gt; If you have any questions or feedback, make sure to comment and let me know!&lt;/p&gt;

&lt;p&gt;I'll be back next week with more. Until then, stay consistent!&lt;/p&gt;

</description>
      <category>react</category>
      <category>programming</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
