<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Reactive Dev 👨‍💻🈺]]></title><description><![CDATA[Hello, World :). I am Martin, a software developer. I am passionate about web development and my favorite stack is Next.js/React.js and Node.js. I do also love ]]></description><link>https://blog.mmwangi.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 23:19:49 GMT</lastBuildDate><atom:link href="https://blog.mmwangi.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Easily Build Real-Time Applications Using NestJS and WebSockets]]></title><description><![CDATA[Introduction
Real-time applications allow instant communication and dynamic interaction between users and systems, such as chat apps, live notifications, and collaborative tools. The core idea is to have immediate updates that keep everyone in sync w...]]></description><link>https://blog.mmwangi.com/how-to-easily-build-real-time-applications-using-nestjs-and-websockets</link><guid isPermaLink="true">https://blog.mmwangi.com/how-to-easily-build-real-time-applications-using-nestjs-and-websockets</guid><category><![CDATA[websockets]]></category><category><![CDATA[nestjs]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Sat, 06 Sep 2025 21:00:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/oqStl2L5oxI/upload/25f909aee79b5b60e8f089838fbe4b00.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Real-time applications allow instant communication and dynamic interaction between users and systems, such as chat apps, live notifications, and collaborative tools. The core idea is to have immediate updates that keep everyone in sync without delays.</p>
<p>WebSockets provide a bidirectional communication protocol to maintain an open connection between client and server, enabling real-time data exchange.</p>
<p>Using NestJS for WebSocket integration simplifies the development of real-time apps by providing structured modules like WebSocket gateways and streamlined event handling. This brings scalability, maintainability, and ease of implementation for developers building high-performance live systems.</p>
<p>To understand more about Nest.js check <a target="_blank" href="https://blog.mmwangi.com/why-nestjs-is-the-ultimate-javascript-backend-framework-for-scalable-clean-and-modular-apps">this article</a></p>
<h2 id="heading-importance-and-benefits-of-using-nestjs-with-websockets">Importance and Benefits of Using NestJS with WebSockets</h2>
<p>Combining NestJS with WebSockets offers several advantages:</p>
<ul>
<li><p><strong>Type Safety</strong>: TypeScript support ensures robust, error-free code</p>
</li>
<li><p><strong>Scalability</strong>: Built-in support for microservices and modular architecture</p>
</li>
<li><p><strong>Developer Experience</strong>: Decorators and dependency injection make code clean and maintainable</p>
</li>
<li><p><strong>Real-time Capabilities</strong>: Seamless WebSocket integration for instant communication</p>
</li>
<li><p><strong>Testing Support</strong>: Built-in testing utilities and mocking capabilities</p>
</li>
</ul>
<p><strong><em>Note:</em></strong> <em>The following article includes code snippets to illustrate various concepts. Please refer to the explanations and additional information in the official documentation.</em></p>
<h2 id="heading-setting-up-the-nestjs-project"><strong>Setting Up the NestJS Project</strong></h2>
<p>Installing NestJS CLI</p>
<pre><code class="lang-bash">npm install -g @nestjs/cli
</code></pre>
<p>Generating a New NestJS Project</p>
<pre><code class="lang-bash">bashnest new real-time-app
<span class="hljs-built_in">cd</span> real-time-app
</code></pre>
<p>The generated project structure:</p>
<pre><code class="lang-typescript">src/
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts
</code></pre>
<p>Update <code>main.ts</code> to enable CORS for our React frontend:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/main.ts</span>
<span class="hljs-keyword">import</span> { NestFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
<span class="hljs-keyword">import</span> { AppModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);

  app.enableCors({
    origin: <span class="hljs-string">'http://localhost:3000'</span>, <span class="hljs-comment">// frontend url</span>
    credentials: <span class="hljs-literal">true</span>,
  });

  <span class="hljs-keyword">const</span> PORT = <span class="hljs-number">3001</span>;
  <span class="hljs-keyword">await</span> app.listen(PORT);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`API running on http://localhost:<span class="hljs-subst">${PORT}</span>`</span>);
}
bootstrap();
</code></pre>
<p>Installing Necessary WebSockets Dependencies</p>
<pre><code class="lang-bash">npm install @nestjs/websockets @nestjs/platform-socket.io socket.io
npm install --save-dev @types/socket.io
</code></pre>
<p>Create a WebSocket gateway:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/chat/chat.gateway.ts</span>
<span class="hljs-keyword">import</span> {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
  OnGatewayInit,
  OnGatewayConnection,
  OnGatewayDisconnect,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/websockets'</span>;
<span class="hljs-keyword">import</span> { Socket, Server } <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io'</span>;
<span class="hljs-keyword">import</span> { Logger } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@WebSocketGateway</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ChatGateway <span class="hljs-keyword">implements</span> OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
  <span class="hljs-keyword">private</span> logger: Logger = <span class="hljs-keyword">new</span> Logger(<span class="hljs-string">'ChatGateway'</span>);
  <span class="hljs-keyword">private</span> connectedClients: <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">string</span>, Socket&gt; = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();

  afterInit(server: Server) {
    <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">'WebSocket Gateway initialized'</span>);
  }

  handleConnection(client: Socket) {
    <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`Client connected: <span class="hljs-subst">${client.id}</span>`</span>);
    <span class="hljs-built_in">this</span>.connectedClients.set(client.id, client);

    <span class="hljs-comment">// Send welcome message</span>
    client.emit(<span class="hljs-string">'connection-success'</span>, {
      message: <span class="hljs-string">'Successfully connected to chat server'</span>,
      clientId: client.id,
    });
  }

  handleDisconnect(client: Socket) {
    <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`Client disconnected: <span class="hljs-subst">${client.id}</span>`</span>);
    <span class="hljs-built_in">this</span>.connectedClients.delete(client.id);
  }

  <span class="hljs-meta">@SubscribeMessage</span>(<span class="hljs-string">'send-message'</span>)
  handleMessage(
    <span class="hljs-meta">@MessageBody</span>() data: { message: <span class="hljs-built_in">string</span>; username: <span class="hljs-built_in">string</span> },
    <span class="hljs-meta">@ConnectedSocket</span>() client: Socket,
  ): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`Message from <span class="hljs-subst">${data.username}</span>: <span class="hljs-subst">${data.message}</span>`</span>);

    <span class="hljs-comment">// Broadcast message to all connected clients</span>
    client.broadcast.emit(<span class="hljs-string">'receive-message'</span>, {
      message: data.message,
      username: data.username,
      timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
      clientId: client.id,
    });
  }

  <span class="hljs-meta">@SubscribeMessage</span>(<span class="hljs-string">'join-room'</span>)
  handleJoinRoom(
    <span class="hljs-meta">@MessageBody</span>() data: { room: <span class="hljs-built_in">string</span>; username: <span class="hljs-built_in">string</span> },
    <span class="hljs-meta">@ConnectedSocket</span>() client: Socket,
  ): <span class="hljs-built_in">void</span> {
    client.join(data.room);
    <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`<span class="hljs-subst">${data.username}</span> joined room: <span class="hljs-subst">${data.room}</span>`</span>);

    client.to(data.room).emit(<span class="hljs-string">'user-joined'</span>, {
      username: data.username,
      room: data.room,
      timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
    });
  }
}
</code></pre>
<p><strong>What's happening here:</strong></p>
<p><code>@WebSocketGateway()</code> marks this class as a WebSocket server that can handle real-time connections from multiple clients simultaneously.</p>
<p><code>@SubscribeMessage('send-message')</code> tells the server to execute the <code>handleMessage</code> method whenever a client sends a message with the event name 'send-message'.</p>
<p><code>@MessageBody()</code> extracts the actual data payload from incoming WebSocket messages, similar to how REST APIs extract JSON from request bodies.</p>
<p><code>@ConnectedSocket()</code> injects the specific client's socket connection into the method, allowing the server to interact with that particular client.</p>
<p><code>client.broadcast.emit()</code> sends messages to all connected clients except the sender, preventing users from seeing their own messages duplicated.</p>
<p><code>client.join(</code><a target="_blank" href="http://data.room"><code>data.room</code></a><code>)</code> adds the client to a specific chat room using <a target="_blank" href="http://Socket.IO">Socket.IO</a>'s built-in room management system.</p>
<p><a target="_blank" href="http://client.to"><code>client.to</code></a><code>(</code><a target="_blank" href="http://data.room"><code>data.room</code></a><code>).emit()</code> sends messages only to clients within a specific room rather than broadcasting to the entire server.</p>
<p><code>Map&lt;string, Socket&gt;</code> stores all active client connections using their unique IDs as keys, enabling the server to track who's online and manage connections efficiently.</p>
<p>The lifecycle methods (<code>afterInit</code>, <code>handleConnection</code>, <code>handleDisconnect</code>) automatically execute when the server starts, clients connect, or clients disconnect, providing hooks for initialization and cleanup tasks.</p>
<p><code>Logger</code> provides structured logging for debugging and monitoring chat activity, tracking connections, messages, and room activities throughout the application.</p>
<p>Create a chat module and register the gateway:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/chat/chat.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ChatGateway } <span class="hljs-keyword">from</span> <span class="hljs-string">'./chat.gateway'</span>;

<span class="hljs-meta">@Module</span>({
  providers: [ChatGateway],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ChatModule {}
</code></pre>
<p><code>providers: [ChatGateway]</code> registers the ChatGateway class with NestJS's dependency injection system, making it available throughout the application.</p>
<p>Update the main app module:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { ChatModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./chat/chat.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [ChatModule],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<h2 id="heading-broadcasting-messages-to-connected-clients">Broadcasting Messages to Connected Clients</h2>
<p>Here's how to implement different broadcasting patterns:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/chat/chat.gateway.ts (extended)</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ChatGateway {
  <span class="hljs-meta">@WebSocketServer</span>()
  server: Server;

  <span class="hljs-comment">// Broadcast to all clients</span>
  <span class="hljs-meta">@SubscribeMessage</span>(<span class="hljs-string">'broadcast-message'</span>)
  broadcastToAll(<span class="hljs-meta">@MessageBody</span>() data: <span class="hljs-built_in">any</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.server.emit(<span class="hljs-string">'global-message'</span>, data);
  }

  <span class="hljs-comment">// Broadcast to specific room</span>
  <span class="hljs-meta">@SubscribeMessage</span>(<span class="hljs-string">'room-message'</span>)
  broadcastToRoom(
    <span class="hljs-meta">@MessageBody</span>() data: { room: <span class="hljs-built_in">string</span>; message: <span class="hljs-built_in">string</span> },
  ): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.server.to(data.room).emit(<span class="hljs-string">'room-message'</span>, data);
  }

  <span class="hljs-comment">// Send to specific client</span>
  sendToClient(clientId: <span class="hljs-built_in">string</span>, event: <span class="hljs-built_in">string</span>, data: <span class="hljs-built_in">any</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> client = <span class="hljs-built_in">this</span>.connectedClients.get(clientId);
    <span class="hljs-keyword">if</span> (client) {
      client.emit(event, data);
    }
  }
}
</code></pre>
<p><code>@WebSocketServer()</code> injects the main <a target="_blank" href="http://Socket.IO">Socket.IO</a> server instance, giving access to all connected clients and server-level operations.</p>
<p><code>this.server.emit()</code> broadcasts messages to every single connected client on the server without any filtering or exclusions.</p>
<p><a target="_blank" href="http://this.server.to"><code>this.server.to</code></a><code>(</code><a target="_blank" href="http://data.room"><code>data.room</code></a><code>).emit()</code> sends messages only to clients who have joined a specific room, enabling targeted group communication.</p>
<p><code>this.connectedClients.get(clientId)</code> retrieves a specific client's socket connection from the stored Map using their unique ID.</p>
<p><code>client.emit(event, data)</code> sends a message directly to one individual client, enabling private messaging or targeted notifications.</p>
<p>The <code>sendToClient</code> method provides programmatic access to send messages to specific users from other parts of the application, not just in response to incoming WebSocket events.</p>
<h2 id="heading-reactjs-frontend-implementation">React.js Frontend Implementation</h2>
<p>Create a React component to interact with the WebSocket server:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/components/ChatComponent.tsx</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { io, Socket } <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;

<span class="hljs-keyword">interface</span> Message {
  message: <span class="hljs-built_in">string</span>;
  username: <span class="hljs-built_in">string</span>;
  timestamp: <span class="hljs-built_in">string</span>;
  clientId: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> ChatComponent: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [socket, setSocket] = useState&lt;Socket | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [messages, setMessages] = useState&lt;Message[]&gt;([]);
  <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [isConnected, setIsConnected] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Initialize socket connection</span>
    <span class="hljs-keyword">const</span> newSocket = io(<span class="hljs-string">'http://localhost:3001'</span>);
    setSocket(newSocket);

    <span class="hljs-comment">// Connection event handlers</span>
    newSocket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function">() =&gt;</span> {
      setIsConnected(<span class="hljs-literal">true</span>);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected to server'</span>);
    });

    newSocket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function">() =&gt;</span> {
      setIsConnected(<span class="hljs-literal">false</span>);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Disconnected from server'</span>);
    });

    newSocket.on(<span class="hljs-string">'connection-success'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connection success:'</span>, data);
    });

    newSocket.on(<span class="hljs-string">'receive-message'</span>, <span class="hljs-function">(<span class="hljs-params">data: Message</span>) =&gt;</span> {
      setMessages(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> [...prev, data]);
    });

    <span class="hljs-comment">// Cleanup on unmount</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      newSocket.close();
    };
  }, []);

  <span class="hljs-keyword">const</span> sendMessage = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (socket &amp;&amp; message.trim() &amp;&amp; username.trim()) {
      socket.emit(<span class="hljs-string">'send-message'</span>, {
        message: message.trim(),
        username: username.trim(),
      });

      <span class="hljs-comment">// Add own message to chat</span>
      setMessages(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> [...prev, {
        message: message.trim(),
        username: username.trim(),
        timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
        clientId: <span class="hljs-string">'self'</span>,
      }]);

      setMessage(<span class="hljs-string">''</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"chat-container"</span>&gt;
      &lt;div className=<span class="hljs-string">"connection-status"</span>&gt;
        Status: {isConnected ? <span class="hljs-string">'🟢 Connected'</span> : <span class="hljs-string">'🔴 Disconnected'</span>}
      &lt;/div&gt;

      &lt;div className=<span class="hljs-string">"user-setup"</span>&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          placeholder=<span class="hljs-string">"Enter your username"</span>
          value={username}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setUsername(e.target.value)}
        /&gt;
      &lt;/div&gt;

      &lt;div className=<span class="hljs-string">"messages-container"</span>&gt;
        {messages.map(<span class="hljs-function">(<span class="hljs-params">msg, index</span>) =&gt;</span> (
          &lt;div key={index} className=<span class="hljs-string">"message"</span>&gt;
            &lt;strong&gt;{msg.username}:&lt;/strong&gt; {msg.message}
            &lt;small&gt;{<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(msg.timestamp).toLocaleTimeString()}&lt;/small&gt;
          &lt;/div&gt;
        ))}
      &lt;/div&gt;

      &lt;div className=<span class="hljs-string">"message-input"</span>&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          placeholder=<span class="hljs-string">"Type your message..."</span>
          value={message}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setMessage(e.target.value)}
          onKeyPress={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e.key === <span class="hljs-string">'Enter'</span> &amp;&amp; sendMessage()}
        /&gt;
        &lt;button onClick={sendMessage}&gt;Send&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ChatComponent;
</code></pre>
<p><code>io('</code><a target="_blank" href="http://localhost:3001"><code>http://localhost:3001</code></a><code>')</code> creates a <a target="_blank" href="http://Socket.IO">Socket.IO</a> client connection to the WebSocket server running on port 3001.</p>
<p><code>useState&lt;Socket | null&gt;(null)</code> manages the socket connection instance in React state, allowing the component to track connection status.</p>
<p><code>useState&lt;Message[]&gt;([])</code> stores all chat messages in an array that updates when new messages arrive.</p>
<p><code>useEffect(() =&gt; {}, [])</code> runs once when the component mounts to initialize the socket connection and set up event listeners.</p>
<p><code>newSocket.on('connect')</code> listens for successful connection events from the server and updates the UI connection status.</p>
<p><code>newSocket.on('receive-message')</code> listens for incoming messages from other users and adds them to the messages array using <code>setMessages(prev =&gt; [...prev, data])</code>.</p>
<p><code>socket.emit('send-message')</code> sends the user's message to the server with the event name that matches the server's <code>@SubscribeMessage('send-message')</code>.</p>
<p><code>setMessages(prev =&gt; [...prev, {...}])</code> adds the user's own message to the chat immediately for instant feedback, since broadcast messages don't include the sender.</p>
<p><code>onKeyPress={(e) =&gt; e.key === 'Enter' &amp;&amp; sendMessage()}</code> allows users to send messages by pressing Enter instead of clicking the button.</p>
<p><code>return () =&gt; { newSocket.close(); }</code> cleans up the socket connection when the component unmounts to prevent memory leaks.</p>
<h2 id="heading-tools-and-techniques-for-efficient-debugging">Tools and Techniques for Efficient Debugging</h2>
<ol>
<li><p><a target="_blank" href="http://Socket.IO"><strong>Socket.IO</strong></a> <strong>Admin UI</strong>: Monitor connections and events</p>
</li>
<li><p><strong>Browser DevTools</strong>: Network tab for WebSocket frames</p>
</li>
<li><p><strong>Logging</strong>: Comprehensive logging for all events</p>
</li>
<li><p><strong>Health Checks</strong>: Monitor server performance</p>
</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// Health check endpoint</span>
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'health'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> HealthController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> chatService: ChatService</span>) {}

  <span class="hljs-meta">@Get</span>(<span class="hljs-string">'websockets'</span>)
  getWebSocketHealth() {
    <span class="hljs-keyword">return</span> {
      activeConnections: <span class="hljs-built_in">this</span>.chatService.getActiveConnections(),
      uptime: process.uptime(),
      timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
    };
  }
}
</code></pre>
<h2 id="heading-best-practices-for-building-real-time-apps">Best Practices for Building Real-Time Apps</h2>
<h3 id="heading-security-considerations">Security Considerations</h3>
<ol>
<li><p><strong>Authentication</strong>: Verify user identity before allowing connections</p>
<pre><code class="lang-typescript"> <span class="hljs-meta">@UseGuards</span>(WsJwtAuthGuard)
 <span class="hljs-meta">@SubscribeMessage</span>(<span class="hljs-string">'send-message'</span>)
 handleMessage() {
   <span class="hljs-comment">// Only authenticated users can send messages</span>
 }
</code></pre>
</li>
<li><p><strong>Rate Limiting</strong>: Prevent spam and DoS attacks</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// Custom rate limiter</span>
 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RateLimitGuard <span class="hljs-keyword">implements</span> CanActivate {
   <span class="hljs-keyword">private</span> requests = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();

   canActivate(context: ExecutionContext): <span class="hljs-built_in">boolean</span> {
     <span class="hljs-keyword">const</span> client = context.switchToWs().getClient();
     <span class="hljs-keyword">const</span> now = <span class="hljs-built_in">Date</span>.now();
     <span class="hljs-keyword">const</span> windowMs = <span class="hljs-number">60000</span>; <span class="hljs-comment">// 1 minute</span>
     <span class="hljs-keyword">const</span> maxRequests = <span class="hljs-number">10</span>;

     <span class="hljs-keyword">const</span> clientRequests = <span class="hljs-built_in">this</span>.requests.get(client.id) || [];
     <span class="hljs-keyword">const</span> validRequests = clientRequests.filter(<span class="hljs-function"><span class="hljs-params">time</span> =&gt;</span> now - time &lt; windowMs);

     <span class="hljs-keyword">if</span> (validRequests.length &gt;= maxRequests) {
       <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
     }

     validRequests.push(now);
     <span class="hljs-built_in">this</span>.requests.set(client.id, validRequests);
     <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
   }
 }
</code></pre>
</li>
<li><p><strong>Input Validation</strong>: Sanitize all incoming data</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// DTO with validation</span>
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SendMessageDto {
   <span class="hljs-meta">@IsString</span>()
   <span class="hljs-meta">@Length</span>(<span class="hljs-number">1</span>, <span class="hljs-number">500</span>)
   message: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@IsString</span>()
   <span class="hljs-meta">@Length</span>(<span class="hljs-number">1</span>, <span class="hljs-number">50</span>)
   username: <span class="hljs-built_in">string</span>;
 }
</code></pre>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>NestJS combined with WebSockets offers a clean, efficient way to build real-time applications that scale. Its modular architecture and built-in support simplify handling live data like chat, notifications, and updates. Paired with React.js for the frontend, it empowers developers to create dynamic, interactive user experiences with minimal complexity.</p>
<p>Exploring NestJS’s advanced features and best practices unlocks even greater potential for real-time app development. This approach is a solid foundation for modern applications seeking seamless real-time communication.</p>
<p><img src="https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExZmJvZ2oxcnU0OWk5OXZlb21vM2plNTd3NThnMHpqc3FsMXhmZXlzbiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/A57xjXNJJiMvgtbBwM/giphy.gif" alt="Moving On Mic Drop GIF by VeeFriends" /></p>
<p>Let me know in the comments if you want a full code example—I'm excited to share it with you!</p>
]]></content:encoded></item><item><title><![CDATA[Why NestJS is the Ultimate JavaScript Backend Framework for Scalable, Clean, and Modular Apps]]></title><description><![CDATA[“TL;DR: If Express and Angular had a baby who grew up on TypeScript and espresso, that baby would be NestJS-and it would already be paying your rent.”
Introduction
JavaScript has come a long way from being just a front-end scripting language. With No...]]></description><link>https://blog.mmwangi.com/why-nestjs-is-the-ultimate-javascript-backend-framework-for-scalable-clean-and-modular-apps</link><guid isPermaLink="true">https://blog.mmwangi.com/why-nestjs-is-the-ultimate-javascript-backend-framework-for-scalable-clean-and-modular-apps</guid><category><![CDATA[nestjs]]></category><category><![CDATA[backend]]></category><category><![CDATA[backend developments]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Sat, 06 Sep 2025 05:00:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/40YHLEhFWq8/upload/99c12dd9f71fe5116b1a62e251d8a5d9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>“TL;DR: If Express and Angular had a baby who grew up on TypeScript and espresso, that baby would be NestJS-and it would already be paying your rent.”</em></p>
<h2 id="heading-introduction">Introduction</h2>
<p>JavaScript has come a long way from being just a front-end scripting language. With Node.js, JavaScript unleashed its power on the backend, empowering developers to build high-performance, event-driven servers using a familiar language. However, as apps grow complex, maintaining clean and scalable backend code can become a headache-it’s like trying to tame a wild octopus with spaghetti arms.</p>
<p>Enter NestJS: the rising star in the JavaScript backend arena. Built on top of Express and optionally Fastify, NestJS applies modern TypeScript and object-oriented programming principles to backend development. Since its debut, it has skyrocketed in popularity for offering a scalable, maintainable architecture that plays well with large teams and complex projects.</p>
<h2 id="heading-the-core-features-of-nestjs">The Core Features of NestJS</h2>
<h3 id="heading-modular-architecture">Modular Architecture</h3>
<p>Modularity is the secret sauce of modern web dev. Splitting the app into distinct modules makes code easier to manage, test, and scale-in other words, less spaghetti and more lasagna layers.</p>
<p>NestJS implements this by letting developers group related components, controllers, and services into modules that can be independently modified or replaced without breaking the whole app.</p>
<h3 id="heading-typescript-support">TypeScript Support</h3>
<p>TypeScript is the superhero cape JavaScript always needed. It adds static typing, early error detection, and improved tooling.</p>
<p>NestJS is built from the ground up with TypeScript, enabling features like autocomplete, refactoring support, and compile-time checks that prevent runtime disasters.</p>
<h3 id="heading-dependency-injection">Dependency Injection</h3>
<p>Dependency Injection (DI) is like the butler for your code, making sure each part gets served exactly what it needs without the components having to fetch it themselves. This pattern helps reduce tight coupling, improves testability, and promotes reusable code.</p>
<p>NestJS’s built-in DI container makes implementing DI straightforward and elegant, encouraging clean architecture even in sprawling codebases.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsService {
  <span class="hljs-keyword">private</span> cats = [];

  findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.cats;
  }
}

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'cats'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> catsService: CatsService</span>) {}

  <span class="hljs-meta">@Get</span>()
  findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.findAll();
  }
}
</code></pre>
<h2 id="heading-scalability-with-nestjs">Scalability with NestJS</h2>
<h3 id="heading-building-scalable-applications">Building Scalable Applications</h3>
<p>Scalability requires a solid foundation. Thanks to its modular design, DI, and support for microservices and asynchronous programming, NestJS shines in building apps that can grow gracefully.</p>
<p>Examples Supporting Scalability</p>
<p>NestJS supports:</p>
<ul>
<li><p>Microservices architecture with support for TCP, Redis, and message brokers like RabbitMQ and Kafka.</p>
</li>
<li><p>WebSockets for real-time communication.</p>
</li>
<li><p>Distributed systems that can handle complex loads without breaking a sweat.</p>
</li>
</ul>
<h3 id="heading-case-studies-of-scalable-applications">Case Studies of Scalable Applications</h3>
<p>From fintech platforms handling thousands of transactions per second to social apps with millions of users, companies like Adidas, Decathlon, and others have adopted NestJS to build their scalable backends. More example here <a target="_blank" href="https://docs.nestjs.com/discover/companies">https://docs.nestjs.com/discover/companies</a>.</p>
<h2 id="heading-clean-and-maintainable-code">Clean and Maintainable Code</h2>
<h3 id="heading-code-organization-in-nestjs">Code Organization in NestJS</h3>
<p>NestJS encourages clear separation of concerns using controllers for routing, services for business logic, and repositories for data access-the famous three-tier architecture.</p>
<h3 id="heading-use-of-decorators-and-metadata">Use of Decorators and Metadata</h3>
<p>Decorators in NestJS add metadata that simplifies configuration and routing without boilerplate. These are inspired by Angular and make your code declarative and readable.</p>
<h3 id="heading-enforcing-coding-standards">Enforcing Coding Standards</h3>
<p>Thanks to TypeScript and standardized architecture, NestJS helps developers consistently write clean and maintainable code, enabling easier onboarding and collaboration.</p>
<h2 id="heading-ecosystem-and-community-support">Ecosystem and Community Support</h2>
<h3 id="heading-overview-of-the-nestjs-ecosystem">Overview of the NestJS Ecosystem</h3>
<p>NestJS’s ecosystem is a Swiss army knife of libraries covering ORM integration (TypeORM, Prisma, Mongoose), authentication (Passport-based), validation, swagger for API docs, and more. Check more here <a target="_blank" href="https://docs.nestjs.com/recipes">https://docs.nestjs.com/recipes</a></p>
<h3 id="heading-libraries-and-plugins">Libraries and Plugins</h3>
<p>Ecosystem plugins include support for <a target="_blank" href="https://docs.nestjs.com/graphql/quick-start">GraphQL</a>, <a target="_blank" href="https://docs.nestjs.com/microservices/basics">microservices</a>, caching, queues, and automatic API documentation generation, streamlining common backend needs.</p>
<h3 id="heading-active-community-and-resources">Active Community and Resources</h3>
<p>NestJS boasts a vibrant community with plenty of tutorials, online courses, and open-source contributions that accelerate learning and problem-solving.</p>
<h2 id="heading-comparisons-with-other-frameworks">Comparisons with Other Frameworks</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>NestJS</strong></td><td><strong>Express.js</strong></td><td><strong>Koa.js</strong></td><td><strong>Other JS Frameworks</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Language Support</td><td>TypeScript first</td><td>JavaScript, TypeScript optional</td><td>JavaScript, minimalistic core</td><td>Varies</td></tr>
<tr>
<td>Architecture</td><td>Modular, DI, MVC</td><td>Minimalistic</td><td>Minimalistic</td><td>Varies</td></tr>
<tr>
<td>Scalability</td><td>High (Microservices ready)</td><td>Moderate</td><td>Moderate</td><td>Varies</td></tr>
<tr>
<td>Built-in Features</td><td>DI, Modules, CLI, GraphQL</td><td>Minimal, middleware only</td><td>Middleware only</td><td>Varies</td></tr>
<tr>
<td>Learning Curve</td><td>Moderate</td><td>Low</td><td>Low</td><td>Varies</td></tr>
</tbody>
</table>
</div><h2 id="heading-real-world-use-cases-of-nestjs">Real-world Use Cases of NestJS</h2>
<h3 id="heading-popular-companies-using-nestjs">Popular Companies Using NestJS</h3>
<ul>
<li><p>Adidas</p>
</li>
<li><p>Decathlon</p>
</li>
<li><p>Roche</p>
</li>
<li><p>Capgemini</p>
</li>
<li><p>Check more here - <a target="_blank" href="https://docs.nestjs.com/discover/companies">https://docs.nestjs.com/discover/companies</a></p>
</li>
</ul>
<h3 id="heading-specific-applications-and-success-stories">Specific Applications and Success Stories</h3>
<ul>
<li><p>Real-time chat apps handling thousands of concurrent users.</p>
</li>
<li><p>Scalable e-commerce backends managing high traffic spikes.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>NestJS offers the best of both worlds: powerful backend capabilities with TypeScript, modular design, and dependency injection, wrapped in a growing supportive ecosystem ideal for scalable and maintainable applications.</p>
<p>Choosing NestJS means betting on a future-proof framework that helps teams build clean, scalable, and robust backend applications with less pain and more joy. Plus, it’s backed by a thriving community that makes the journey even more enjoyable.</p>
<p><img src="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExYjB6ZDFnZXZ4YnF2ZDhtMmI1MHBlcGhzdjFjNzdwY3Z4dXAyZzl3MyZlcD12MV9naWZzX3NlYXJjaCZjdD1n/X8ae2ViYY7rk4eWzcl/giphy.gif" alt="Nickelodeon Trying GIF by Paramount+" /></p>
<p>Want to build scalable applications powered by NestJs?</p>
<p>Contact us here <a target="_blank" href="https://www.mcdorcis.com/">https://www.mcdorcis.com/</a></p>
]]></content:encoded></item><item><title><![CDATA[Handling Forms in React Using React Hook Form  ZOD and TypeScript]]></title><description><![CDATA[One major part of dealing with forms as a developer is validating the different inputs you have. When dealing with simple forms, things are generally manageable. But as your form gets more complex with more inputs and you need to add various validati...]]></description><link>https://blog.mmwangi.com/handling-forms-in-react-using-react-hook-form-zod-and-typescript</link><guid isPermaLink="true">https://blog.mmwangi.com/handling-forms-in-react-using-react-hook-form-zod-and-typescript</guid><category><![CDATA[Next.js]]></category><category><![CDATA[react-hook-form]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Thu, 15 Aug 2024 11:32:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/gEN5Btvf2Eg/upload/0521e809dd7bfb660e0f5577da74bfd3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One major part of dealing with forms as a developer is validating the different inputs you have. When <a target="_blank" href="https://blog.thereactivedeveloper.com/form-handling-in-reactjs">dealing with simple forms</a>, things are generally manageable. But as your form gets more complex with more inputs and you need to add various validations, it becomes a complicated task.</p>
<p>Instead of writing all the logic and validation rules in your forms manually, we can make use of libraries such as <code>react-hook-form</code> or <code>formik</code>. In this post, we are going to look at handling and validating forms in a React application using <code>react-hook-form</code></p>
<h2 id="heading-what-is-react-hook-form">What is React Hook Form</h2>
<p>React Hook Form is a library that helps you validate forms in React. It is a minimal library without any other dependencies while being performant and straightforward to use, requiring developers to write fewer lines of code than other form libraries.</p>
<p>It takes a slightly different approach than other form libraries in the React ecosystem by adopting the use of uncontrolled inputs using <code>ref</code> instead of depending on the state to control the inputs. This approach makes the forms more performant and reduces the number of re-renders.</p>
<p>To install React Hook Form, run the following command:</p>
<pre><code class="lang-bash">npm install react-hook-form
</code></pre>
<p>Check my previous blog <a target="_blank" href="https://blog.thereactivedeveloper.com/form-handling-in-reactjs">here</a> to read more on handling forms in React without using a library</p>
<h2 id="heading-what-is-zod">What is ZOD</h2>
<p>Zod is a JavaScript validation library that allows you to define schemas that model the shape and constraints of your data. These schemas generate type safety, automatic validation, and useful error messages. Some key aspects of Zod include:</p>
<ul>
<li><p>Validation of data types, strings, numbers, objects etc.</p>
</li>
<li><p>Customizable error messages</p>
</li>
<li><p>Support for nested objects and arrays</p>
</li>
<li><p>Code auto-completion when using a Zod schema</p>
</li>
<li><p>Type safety with TypeScript integration</p>
</li>
</ul>
<p>By modeling application data with Zod schemas, you get built-in validation with helpful errors. It makes it easy to reuse validation logic across your application.</p>
<p>To work with Zod in React, you need to install the library and a resolver</p>
<pre><code class="lang-bash">npm install @hookform/resolvers zod
</code></pre>
<h2 id="heading-setting-up-our-form">Setting Up Our Form</h2>
<ol>
<li>Import the required components and hooks:</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-hook-form'</span>;
<span class="hljs-keyword">import</span> { zodResolver } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hookform/resolvers/zod'</span>;
<span class="hljs-keyword">import</span> { z } <span class="hljs-keyword">from</span> <span class="hljs-string">'zod'</span>;
</code></pre>
<ol start="2">
<li><p>Define your form schema using Zod:</p>
<p> Zod allows us to define a schema that lays out the exact shape and constraints we want to apply to our form data. Let's create one for our form:</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createUserSchema = z.object({
   name: z.string().min(<span class="hljs-number">2</span>, { message: <span class="hljs-string">'Name is required'</span> }),
   email: z.string().email(<span class="hljs-string">'Must be a valid email'</span>),
   age: z.number().positive().int(),
 });
</code></pre>
<p> This schema defines the fields we expect along with constraints like minimum length, email validation, etc. Zod will automatically generate useful error messages for us when validation fails.</p>
</li>
<li><p>Create form component:</p>
<p> Using the schema we created above, we can create form with corresponding inputs as illustrated below.</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">type</span> FormData = z.infer&lt;<span class="hljs-keyword">typeof</span> createUserSchema&gt;;

 <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserForm</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> {
     register,
     handleSubmit,
     formState: { errors },
   } = useForm&lt;FormData&gt;({
     resolver: zodResolver(createUserSchema),
   });

   <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-function">(<span class="hljs-params">data: FormData</span>) =&gt;</span> {
     <span class="hljs-built_in">console</span>.log(data);
     <span class="hljs-comment">// Handle form submission</span>
   };

   <span class="hljs-keyword">return</span> (
     &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
       &lt;div&gt;
         &lt;label htmlFor=<span class="hljs-string">"name"</span>&gt;Name&lt;/label&gt;
         &lt;input id=<span class="hljs-string">"name"</span> {...register(<span class="hljs-string">'name'</span>)} /&gt;
         {errors.name &amp;&amp; &lt;span&gt;{errors.name.message}&lt;/span&gt;}
       &lt;/div&gt;

       &lt;div&gt;
         &lt;label htmlFor=<span class="hljs-string">"email"</span>&gt;Email&lt;/label&gt;
         &lt;input id=<span class="hljs-string">"email"</span> {...register(<span class="hljs-string">'email'</span>)} /&gt;
         {errors.email &amp;&amp; &lt;span&gt;{errors.email.message}&lt;/span&gt;}
       &lt;/div&gt;

       &lt;div&gt;
         &lt;label htmlFor=<span class="hljs-string">"age"</span>&gt;Age&lt;/label&gt;
         &lt;input id=<span class="hljs-string">"age"</span> <span class="hljs-keyword">type</span>=<span class="hljs-string">"number"</span> {...register(<span class="hljs-string">'age'</span>, { valueAsNumber: <span class="hljs-literal">true</span> })} /&gt;
         {errors.age &amp;&amp; &lt;span&gt;{errors.age.message}&lt;/span&gt;}
       &lt;/div&gt;

       &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Submit&lt;/button&gt;
     &lt;/form&gt;
   );
 }
</code></pre>
<p> Here is what's happening:</p>
<ul>
<li><p>We use <code>z.infer&lt;typeof createUserSchema&gt;</code> to infer the TypeScript type from our Zod schema.</p>
</li>
<li><p>The <code>useForm</code> hook is initialized with the zodResolver, which connects React Hook Form with our Zod schema.</p>
</li>
<li><p>We destructure <code>register</code>, <code>handleSubmit</code>, and <code>errors</code> from the <code>useForm</code> hook.</p>
</li>
<li><p>The <code>register</code> function is used to register our inputs with React Hook Form.</p>
</li>
<li><p>We display error messages conditionally based on the <code>errors</code> object.</p>
</li>
<li><p>We use the <code>handleSubmit</code> method connect to our own <code>onSubmit</code> method to handle form submission. The <code>onSubmit</code> method will be called when all validation passes and will receive the form data which you can handle as needed such as submitting it to an api.</p>
</li>
</ul>
</li>
<li><p>Advanced Usage:</p>
<p> React Hook Form and Zod offer more advanced features that you can explore:</p>
<ul>
<li><p>Custom error messages</p>
</li>
<li><p>Conditional fields</p>
</li>
<li><p>Array fields</p>
</li>
<li><p>Async validation</p>
</li>
</ul>
</li>
</ol>
<p>    Here's an example of a more complex schema with custom error messages:</p>
<pre><code class="lang-typescript">    <span class="hljs-keyword">const</span> advancedSchema = z.object({
      username: z.string()
        .min(<span class="hljs-number">3</span>, { message: <span class="hljs-string">'Username must be at least 3 characters long'</span> })
        .max(<span class="hljs-number">20</span>, { message: <span class="hljs-string">'Username cannot exceed 20 characters'</span> }),
      password: z.string()
        .min(<span class="hljs-number">8</span>, { message: <span class="hljs-string">'Password must be at least 8 characters long'</span> })
        .regex(<span class="hljs-regexp">/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/</span>, {
          message: <span class="hljs-string">'Password must contain at least one uppercase letter, one lowercase letter, and one number'</span>
        }),
      confirmPassword: z.string(),
    }).refine(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> data.password === data.confirmPassword, {
      message: <span class="hljs-string">"Passwords don't match"</span>,
      path: [<span class="hljs-string">"confirmPassword"</span>],
    });
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Using React Hook Form with Zod provides a powerful and type-safe way to handle form validation in React applications. This combination offers several benefits:</p>
<ol>
<li><p>Reduced boilerplate code</p>
</li>
<li><p>Improved performance with uncontrolled components</p>
</li>
<li><p>Strong typing and IntelliSense support</p>
</li>
<li><p>Flexible and extensible validation rules</p>
</li>
</ol>
<p>By leveraging these libraries, you can create robust forms with complex validation logic while maintaining clean and maintainable code. As your forms grow in complexity, these tools will help you manage that complexity efficiently.</p>
<p>Remember to always refer to the official documentation of <a target="_blank" href="https://react-hook-form.com/">React Hook Form</a> and <a target="_blank" href="https://zod.dev/">Zod</a> for the most up-to-date information and advanced usage scenarios.</p>
<p><img src="https://media2.giphy.com/media/3oEduU0P4xaRiHyGbe/200.gif?cid=ecf05e4708r1xj5dmrsjw602iz20rpa4x7fn36t2xw9ekzyz&amp;ep=v1_gifs_search&amp;rid=200.gif&amp;ct=g" alt="peace out goodbye GIF by Red Bull" /></p>
<p>Keep coding :)</p>
<p>🤖</p>
]]></content:encoded></item><item><title><![CDATA[Reviving Resolutions: The .NET Odyssey Begins]]></title><description><![CDATA[Introduction
Ever found yourself at the end of the year, pondering those New Year's resolutions made with unwavering determination? We all do it. Those grand plans we enthusiastically set when the year was fresh and brimming with potential, only to w...]]></description><link>https://blog.mmwangi.com/reviving-resolutions-the-net-odyssey-begins</link><guid isPermaLink="true">https://blog.mmwangi.com/reviving-resolutions-the-net-odyssey-begins</guid><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Mon, 16 Oct 2023 21:00:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/AXc2uwl4Cik/upload/229d4fa113df67708f516b769a33765f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p>Ever found yourself at the end of the year, pondering those New Year's resolutions made with unwavering determination? We all do it. Those grand plans we enthusiastically set when the year was fresh and brimming with potential, only to watch them slowly fade into the background as life takes over. But here's the million-dollar question: Is it too late to salvage those dreams, the ones we stashed away in our bucket list? You know, like that one thing I've always wanted to do - mastering .NET for web APIs. And trust me, I'm not alone in this rollercoaster of ambition and distraction. Life has a way of side-tracking us from our grand intentions, but here's the good news, folks: the year's not over, and there's still time to make some headway. So, hang onto your hats, because I'm thrilled to unveil a brand-new series - "The .Net Odyssey."</p>
<p><img src="https://media1.giphy.com/media/C2V3bklNmp9K/200.gif?cid=ecf05e47djvwnkoashopfsffzlm2j543c0vgsjbafeawa89g&amp;ep=v1_gifs_search&amp;rid=200.gif&amp;ct=g" alt="hustle hustling GIF" /></p>
<h3 id="heading-daily-learning-hustle"><strong>Daily Learning Hustle</strong></h3>
<p>Okay, so here's the deal – I've made it a mission to learn .NET every single day. Yep, you heard me right, every single day. And let me tell you, it's been a real rollercoaster. Some days, I'm crushing those APIs like a champ. Other days, it feels like the code's playing pranks on me. But here's the thing, I'm not backing down, and I don't want you to either. If you're in the same boat, know that I'm right there with you, learning and laughing through it all.</p>
<h3 id="heading-the-weekly-adventure"><strong>The Weekly Adventure</strong></h3>
<p>To keep things manageable, I'm tackling .NET one week at a time. Each week, I dive into a different piece of the .NET puzzle. It's like going on an all-you-can-eat buffet, except it's a buffet of tech knowledge, and I'm the hungry explorer. From web API basics to the crazier stuff, I'm sharing all the wins and facepalms along the way.</p>
<h3 id="heading-monthly-check-ins"><strong>Monthly Check-Ins</strong></h3>
<p>At the end of each month, I'm raising a toast to my small victories and epic flops. Because, let's be real, it's all part of the game. Learning .NET is about more than just code; it's about embracing the journey, the quirks, and the discoveries – and I wouldn't have it any other way.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Now, in case you're thinking I'm about to lay out a detailed roadmap to help you nail your resolutions, think again. Instead, I'm extending an invitation – one to savor the ride, explore the unknown, and find joy in the process. For me, mastering .NET for web APIs is not just about code; it's about enjoying the journey. Come aboard, join me on this exhilarating ride, and together, we'll face those resolutions with a smile. Remember, it's not just about the destination; it's all about the adventure itself! What's your learning journey been like? Share your experiences with me and let's continue this conversation.</p>
<p>Plus</p>
<p><img src="https://media2.giphy.com/media/fKYdL6Sb3gnJJyrQ7z/200w.gif?cid=ecf05e47rn8mjvfn1c0ecpbpfm0p1vpva919wyuio3vavaci&amp;ep=v1_gifs_search&amp;rid=200w.gif&amp;ct=g" alt="Dont Be Late Lets Go GIF by The Democrats" /></p>
<p>So see yah at the next one</p>
<p>🤖</p>
]]></content:encoded></item><item><title><![CDATA[Font optimization in Next.js 13]]></title><description><![CDATA[Introduction
When creating a website with performance and SEO as key features, font optimization becomes a crucial consideration. In the ever-evolving world of web development, where user experience and page load times are paramount, even the smalles...]]></description><link>https://blog.mmwangi.com/font-optimization-in-nextjs-13</link><guid isPermaLink="true">https://blog.mmwangi.com/font-optimization-in-nextjs-13</guid><category><![CDATA[Next.js]]></category><category><![CDATA[optimization]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Sat, 09 Sep 2023 19:00:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/M9NVqELEtHU/upload/0c9af2c4f6dac82926dbf216772a6ea1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>When creating a website with performance and SEO as key features, font optimization becomes a crucial consideration. In the ever-evolving world of web development, where user experience and page load times are paramount, even the smallest details can make a significant impact. One such detail that often gets overlooked is the way we handle fonts.</p>
<p>Fonts play an integral role in shaping the visual identity of a website. They set the tone, convey the brand's personality, and ensure that the content is not only legible but also aesthetically pleasing. However, if not optimized properly, fonts can become a performance bottleneck, causing slow page load times and potentially harming your search engine rankings.</p>
<p>In this blog post, we'll delve into the world of font optimization in the context of Next.js 13, my favorite framework for building modern, server-rendered React applications. We'll explore why font optimization matters, the challenges it presents, and practical techniques and tools to streamline font delivery, minimize performance impact, and enhance your website's SEO.</p>
<h2 id="heading-why-font-optimization-matters"><strong>Why Font Optimization Matters</strong></h2>
<p>Before we dive into the specifics of font optimization in Next.js 13, let's understand why it matters in the first place.</p>
<ol>
<li><p><strong>Page Load Speed</strong>: Research shows that users expect websites to load in a matter of seconds. Slow-loading websites leads to higher bounce rates, lower user engagement, and decreased conversions. Unoptimized fonts can significantly contribute to page load times, as they are additional resources that need to be fetched and rendered.</p>
</li>
<li><p><strong>Mobile Responsiveness</strong>: With the increasing use of mobile devices for browsing, optimizing fonts becomes even more critical. Mobile networks can be slower than broadband connections and mobile devices have limited processing power. Optimized fonts ensure a smoother experience for mobile users.</p>
</li>
<li><p><strong>SEO Rankings</strong>: Search engines like Google consider page speed as a ranking factor. Faster websites tend to rank higher in search results. Therefore, optimizing fonts can indirectly impact your SEO rankings and organic traffic.</p>
</li>
<li><p><strong>User Experience</strong>: Fonts affect the overall look and feel of your website. If fonts are not optimized and cause layout shifts or visual glitches during loading, it can create a poor user experience, leading to user frustration.</p>
</li>
</ol>
<p>To handle font optimization, Next.js introduces <code>next/font</code> which assists in making sure fonts are loaded efficiently on your website.</p>
<h2 id="heading-what-is-nextfont">What is next/font?</h2>
<p>Next/font gives you the ability to optimally and painlessly load fonts within your Next.js website.</p>
<p><a target="_blank" href="https://nextjs.org/docs/pages/building-your-application/optimizing/fonts"><strong>[From Docs]</strong></a> next/font system also allows you to conveniently use all Google Fonts with performance and privacy in mind. CSS and font files are downloaded at build time and self-hosted with the rest of your static assets. <strong>No requests are sent to Google by the browser.</strong></p>
<p>There are a few requirements needed for you to be able to use next/font:</p>
<ol>
<li><p><strong>You must be using Next 13 (or newer)</strong></p>
</li>
<li><p><strong>You must be using a Google font or a local font.</strong></p>
</li>
</ol>
<p>If you’re not using Next 13, or need a different font library then <a target="_blank" href="https://fontsource.org/docs/introduction"><strong>Fontsource</strong></a> is a great alternative, but it requires a little more configuration.</p>
<h2 id="heading-how-to-optimise-fonts-with-nextfont">How to optimise fonts with next/font</h2>
<p>Next/font is already included in Next.js directly and we don't need to install any package to use it.</p>
<p>Like I mentioned above, next/font provides two way of importing fonts, either google fonts or local fonts. Regardless of whether we are using google or local font's, we can use fonts in two ways:</p>
<ul>
<li><p>Import them globally (recommended)</p>
</li>
<li><p>Import them on individual pages</p>
</li>
</ul>
<h3 id="heading-using-google-fonts">Using Google Fonts</h3>
<p>This allows us to automatically self-host any Google Font within our deployment. With this feature, the fonts become an intrinsic part of the deployment package and are seamlessly served from the same domain as your website. Consequently, there is no necessity for the browser to dispatch requests to Google's servers. This not only streamlines font delivery but also enhances both the performance and privacy of your web application.</p>
<p>Get started by importing the font you would like to use from <code>next/font/google</code> as a function.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//app/layout.tsx</span>
<span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/google'</span>

<span class="hljs-comment">// If loading a variable font, you don't need to specify the font weight</span>
<span class="hljs-keyword">const</span> inter = Inter({
  subsets: [<span class="hljs-string">'latin'</span>],
  display: <span class="hljs-string">'swap'</span>,
})

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{
  children,
}: {
  children: React.ReactNode
}</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span> className={inter.className}&gt;
      &lt;body&gt;{children}&lt;/body&gt;
    &lt;/html&gt;
  )
}
</code></pre>
<p>To learn more about using Google fonts, check <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/optimizing/fonts#google-fonts">here</a></p>
<h3 id="heading-using-local-fonts">Using Local fonts</h3>
<p>Import <code>next/font/local</code> and specify the <code>src</code> of your local font file. Like Google Fonts, it’s recommended to use <a target="_blank" href="https://fonts.google.com/variablefonts">variable fonts</a> if possible.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//app/layout.tsx</span>
<span class="hljs-keyword">import</span> localFont <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/local'</span>

<span class="hljs-comment">// Font files can be colocated inside of `app`</span>
<span class="hljs-keyword">const</span> myFont = localFont({
  src: <span class="hljs-string">'./my-font.woff2'</span>,
  display: <span class="hljs-string">'swap'</span>,
})

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{
  children,
}: {
  children: React.ReactNode
}</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span> className={myFont.className}&gt;
      &lt;body&gt;{children}&lt;/body&gt;
    &lt;/html&gt;
  )
}
</code></pre>
<p>If you can’t use a variable font, you’ll likely need to import a handful of font files which you can do by including them as an array.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> roboto = localFont({
  src: [
    {
      path: <span class="hljs-string">'./Roboto-Regular.woff2'</span>,
      weight: <span class="hljs-string">'400'</span>,
      style: <span class="hljs-string">'normal'</span>,
    },
    {
      path: <span class="hljs-string">'./Roboto-Italic.woff2'</span>,
      weight: <span class="hljs-string">'400'</span>,
      style: <span class="hljs-string">'italic'</span>,
    },
    {
      path: <span class="hljs-string">'./Roboto-Bold.woff2'</span>,
      weight: <span class="hljs-string">'700'</span>,
      style: <span class="hljs-string">'normal'</span>,
    },
    {
      path: <span class="hljs-string">'./Roboto-BoldItalic.woff2'</span>,
      weight: <span class="hljs-string">'700'</span>,
      style: <span class="hljs-string">'italic'</span>,
    },
  ],
})
</code></pre>
<p>You can check out <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/optimizing/fonts#local-fonts">here</a> for more details about using local fonts.</p>
<h2 id="heading-with-tailwind-css">With Tailwind CSS</h2>
<p>Like any other tool, we would like to make it easier to work with our favorite styling library. <code>next/font</code> can be used with <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a> through a <a target="_blank" href="https://nextjs.org/docs/app/api-reference/components/font#css-variables">CSS variable</a>.</p>
<p>In the example below, we use the font <code>Inter</code> from <code>next/font/google</code> (you can use any font from Google or Local Fonts). Load your font with the <code>variable</code> option to define your CSS variable name and assign it to <code>inter</code>. Then, use <code>inter.variable</code> to add the CSS variable to your HTML document.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//app/layout.tsx</span>
<span class="hljs-keyword">import</span> { Inter, Roboto_Mono } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/google'</span>

<span class="hljs-keyword">const</span> inter = Inter({
  subsets: [<span class="hljs-string">'latin'</span>],
  display: <span class="hljs-string">'swap'</span>,
  variable: <span class="hljs-string">'--font-inter'</span>,
})

<span class="hljs-keyword">const</span> roboto_mono = Roboto_Mono({
  subsets: [<span class="hljs-string">'latin'</span>],
  display: <span class="hljs-string">'swap'</span>,
  variable: <span class="hljs-string">'--font-roboto-mono'</span>,
})

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{
  children,
}: {
  children: React.ReactNode
}</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span> className={<span class="hljs-string">`<span class="hljs-subst">${inter.variable}</span> <span class="hljs-subst">${roboto_mono.variable}</span>`</span>}&gt;
      &lt;body&gt;{children}&lt;/body&gt;
    &lt;/html&gt;
  )
}
</code></pre>
<p>Finally, add the CSS variable to your <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/styling/tailwind-css#configuring-tailwind">Tailwind CSS config</a>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// tailwind.config.js</span>
<span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">'./pages/**/*.{js,ts,jsx,tsx}'</span>,
    <span class="hljs-string">'./components/**/*.{js,ts,jsx,tsx}'</span>,
    <span class="hljs-string">'./app/**/*.{js,ts,jsx,tsx}'</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {
      <span class="hljs-attr">fontFamily</span>: {
        <span class="hljs-attr">sans</span>: [<span class="hljs-string">'var(--font-inter)'</span>],
        <span class="hljs-attr">mono</span>: [<span class="hljs-string">'var(--font-roboto-mono)'</span>],
      },
    },
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>You can now use the <code>font-sans</code> and <code>font-mono</code> utility classes to apply the font to your elements.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It’s as easy as that. Now you’ve got next/font set up you can be certain that you’re loading fonts most optimally across your entire project with minimal effort.</p>
<p><img src="https://media2.giphy.com/media/3oEduU0P4xaRiHyGbe/200.gif?cid=ecf05e4708r1xj5dmrsjw602iz20rpa4x7fn36t2xw9ekzyz&amp;ep=v1_gifs_search&amp;rid=200.gif&amp;ct=g" alt="peace out goodbye GIF by Red Bull" /></p>
<p>Keep coding :)</p>
<p>🤖</p>
]]></content:encoded></item><item><title><![CDATA[Create a blog website using NextJs and Keystatic - Working with Keystatic (Part 2)]]></title><description><![CDATA[Welcome back to our journey of creating a blog website using Next.js and Keystatic! In Part 1, we laid the foundation by setting up our project and integrating Keystatic. Now, in Part 2, we're going to dive deeper into the Keystatic ecosystem and lea...]]></description><link>https://blog.mmwangi.com/create-a-blog-website-using-nextjs-and-keystatic-working-with-keystatic-part-2</link><guid isPermaLink="true">https://blog.mmwangi.com/create-a-blog-website-using-nextjs-and-keystatic-working-with-keystatic-part-2</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Keystatic]]></category><category><![CDATA[nextjs 13.4]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Blogging]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Fri, 01 Sep 2023 21:16:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/xG8IQMqMITM/upload/204f7cb51a15086dccd103aace6d845d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome back to our journey of creating a blog website using Next.js and Keystatic! In <a target="_blank" href="https://blog.thereactivedeveloper.com/create-a-blog-website-using-nextjs-and-keystatic-setup-part-1">Part 1</a>, we laid the foundation by setting up our project and integrating Keystatic. Now, in Part 2, we're going to dive deeper into the Keystatic ecosystem and learn how to work with it to manage and display content on our Next.js front end.</p>
<h2 id="heading-keystatic-configuration">Keystatic Configuration</h2>
<p>Every Keystatic project expects an exported <code>config</code>. The <code>config()</code> function can be imported from the <code>@keystatic/core</code> package:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// keystatic.config.ts</span>
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config({
  <span class="hljs-comment">// ...</span>
})
</code></pre>
<h3 id="heading-configuration-options"><strong>Configuration options</strong></h3>
<p>Keystatic's <code>config</code> requires at minimum a <code>storage</code> strategy.</p>
<p>It can also define <code>collections</code> and <code>singletons</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// keystatic.config.ts</span>
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config({
  <span class="hljs-comment">// Required</span>
  storage: { kind: <span class="hljs-string">'local'</span> },
  <span class="hljs-comment">// Optional</span>
  collections: {},
  singletons: {}
})
</code></pre>
<h3 id="heading-collections">Collections</h3>
<p>Picture collections as a way to assemble a bunch of instances of something you hold dear. It's like curating a series of blog posts, your favorite cooking recipes, or heartwarming testimonials from content customers.</p>
<p>Collections find their definition in the collections section of the Keystatic config. Each collection possesses its distinct key and is enveloped within the collection() function.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// keystatic.config.ts</span>
<span class="hljs-keyword">import</span> { config, collection } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config({
  <span class="hljs-comment">// ...</span>
  collections: {
    posts: collection({
      label: <span class="hljs-string">'Posts'</span>,
      slugField: <span class="hljs-string">'author'</span>,
      schema: {
        author: fields.slug({ name: { label: <span class="hljs-string">'Author'</span> } }),
        quote: fields.text({ label: <span class="hljs-string">'Quote'</span>, multiline: <span class="hljs-literal">true</span> })
      }
    }),
  },
});
</code></pre>
<p>To learn more check out the <a target="_blank" href="https://keystatic.com/docs/collections">official documentation</a></p>
<h3 id="heading-singletons">Singletons</h3>
<p>When you're after a truly one-of-a-kind data entry, think of scenarios like crafting a dedicated "Settings" page or sculpting a finely-tailored set of fields for the cherished "Homepage" of a website. This is where singletons step in.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// keystatic.config.ts</span>
<span class="hljs-keyword">import</span> { config, singleton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config({
  <span class="hljs-comment">// ...</span>
  singletons: {
    settings: singleton({
      label: <span class="hljs-string">'Settings'</span>,
      schema: {}
    }),
  },
});
</code></pre>
<p>To learn more about singletons check out the <a target="_blank" href="https://keystatic.com/docs/singletons">official documentation</a></p>
<p>Another key part of Keystatic that is crucial is the field types. Keystatic has several fields that can be used in different scenarios depending on your use case. To learn about all the fields, I recommend you check <a target="_blank" href="https://keystatic.com/docs/fields/array">here</a>.</p>
<p>Now let's get started setting up Keystatic with a schema we will use for the blog.</p>
<p>Here is the new configuration that meets our requirements.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// keystatic.config.ts</span>
<span class="hljs-keyword">import</span> { config, fields, singleton, collection } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config({
    storage: {
        kind: <span class="hljs-string">'local'</span>,
    },
    singletons: {
        homepage: singleton({
            label: <span class="hljs-string">'HomeTitle'</span>,
            path: <span class="hljs-string">'src/content/homepage'</span>,
            schema: {
                headline: fields.text({ label: <span class="hljs-string">'HomeText'</span> }),
            },
        }),
    },/
    collections: {
        articles: collection({
            slugField: <span class="hljs-string">"path"</span>,
            label: <span class="hljs-string">'Articles'</span>,
            path: <span class="hljs-string">'src/content/collections/articles/*/'</span>,
            schema: {
                path: fields.slug({name: {label: <span class="hljs-string">'path'</span>}}),
                title: fields.text({label: <span class="hljs-string">'Title'</span>}),
                cover: fields.image({
                    label: <span class="hljs-string">'Cover Image'</span>,
                    directory: <span class="hljs-string">'public/images/avatars'</span>,
                    publicPath: <span class="hljs-string">'/images/avatars/'</span>
                }),
                date: fields.date({label: <span class="hljs-string">'Date'</span>}),
                text: fields.document({
                    label: <span class="hljs-string">'Text'</span>,
                    formatting: <span class="hljs-literal">true</span>,
                    links: <span class="hljs-literal">true</span>,
                    dividers: <span class="hljs-literal">true</span>,
                    tables: <span class="hljs-literal">true</span>,
                    images: <span class="hljs-literal">true</span>,
                }),
            }
        }),
    }
})
</code></pre>
<p>Let's break down the code:</p>
<p>We first declare that our content will be stored locally. You can also store your content on a Github repository with Keystatic.</p>
<pre><code class="lang-typescript">storage: {
    kind: <span class="hljs-string">'local'</span>,
},
</code></pre>
<p>The singletons part represents a single piece of data. For our case the title of the website. You must provide a label and a schema, as well as the format of our data. Our title will be a simple text line in this case. We also specify where our content will be stored.</p>
<pre><code class="lang-typescript">singletons: {
        homepage: singleton({
            label: <span class="hljs-string">'HomeTitle'</span>,
            path: <span class="hljs-string">'src/content/homepage'</span>,
            schema: {
                headline: fields.text({ label: <span class="hljs-string">'HomeText'</span> }),
            },
        }),
    },
</code></pre>
<p>The next part involves configuring a collection for our articles/blogs. Some properties can be used to define our articles. Each article will have a title, an image to illustrate it, a publication date, and finally a content text. The text options will allow us to include links, tables, images, and so on.</p>
<pre><code class="lang-typescript">collections: {
        articles: collection({
            slugField: <span class="hljs-string">"path"</span>,
            label: <span class="hljs-string">'Articles'</span>,
            path: <span class="hljs-string">'src/content/collections/articles/*/'</span>,
            schema: {
                path: fields.slug({name: {label: <span class="hljs-string">'path'</span>}}),
                title: fields.text({label: <span class="hljs-string">'Title'</span>}),
                cover: fields.image({
                    label: <span class="hljs-string">'Cover Image'</span>,
                    directory: <span class="hljs-string">'public/images/avatars'</span>,
                    publicPath: <span class="hljs-string">'/images/avatars/'</span>
                }),
                date: fields.date({label: <span class="hljs-string">'Date'</span>}),
                text: fields.document({
                    label: <span class="hljs-string">'Text'</span>,
                    formatting: <span class="hljs-literal">true</span>,
                    links: <span class="hljs-literal">true</span>,
                    dividers: <span class="hljs-literal">true</span>,
                    tables: <span class="hljs-literal">true</span>,
                    images: <span class="hljs-literal">true</span>,
                }),
            }
        }),
    }
</code></pre>
<p>We can now restart our application and visit <code>http://localhost:3000/keystatic</code> to view the new configurations and update the data.</p>
<p>Your dashboard should look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1693596507938/4ef3b074-8402-48ee-8824-68557fe44736.png" alt class="image--center mx-auto" /></p>
<p>When you click on articles and the add button. You should be presented with a form with all the inputs we configured.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1693596559315/36d3bb1f-bffe-433d-b42b-b82830379581.png" alt class="image--center mx-auto" /></p>
<p>You can go ahead and add several sample articles.</p>
<h2 id="heading-rendering-keystatic-content">Rendering Keystatic content</h2>
<p>To render our content, we can make use of the Keystatic <a target="_blank" href="https://keystatic.com/docs/reader-api">Reader API</a> which must be run server-side.</p>
<h3 id="heading-displaying-a-collection-list">Displaying a collection list</h3>
<p>The following example displays a list of each post title, with a link to an individual post page:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/page.tsx</span>
<span class="hljs-keyword">import</span> { createReader } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core/reader'</span>;
<span class="hljs-keyword">import</span> keystaticConfig <span class="hljs-keyword">from</span> <span class="hljs-string">'../../keystatic.config'</span>;

<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>;

<span class="hljs-comment">// 1. Create a reader</span>
<span class="hljs-keyword">const</span> reader = createReader(process.cwd(), keystaticConfig);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// 2. Read the "articles" collection</span>
  <span class="hljs-keyword">const</span> articles = <span class="hljs-keyword">await</span> reader.collections.articles.all();
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"max-w-[1200px] mx-auto p-4"</span>&gt;
      &lt;ul className=<span class="hljs-string">""</span>&gt;
        {articles.map(<span class="hljs-function"><span class="hljs-params">article</span> =&gt;</span> (
          &lt;li&gt;
            &lt;Link className=<span class="hljs-string">"shadow block w-[300px] p-4"</span> href={<span class="hljs-string">`/<span class="hljs-subst">${article.slug}</span>`</span>}&gt;{article.entry.title}&lt;/Link&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h3 id="heading-displaying-a-single-collection-entry">Displaying a single collection entry</h3>
<p>To display content from an individual post, you can import and use Keystatic's <code>&lt;DocumentRenderer /&gt;</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/[slug]/page.tsx</span>
<span class="hljs-keyword">import</span> { createReader } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core/reader'</span>;
<span class="hljs-keyword">import</span> { DocumentRenderer } <span class="hljs-keyword">from</span> <span class="hljs-string">"@keystatic/core/renderer"</span>;
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> { notFound } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/navigation"</span>;
<span class="hljs-keyword">import</span> keystaticConfig <span class="hljs-keyword">from</span> <span class="hljs-string">"../../../keystatic.config"</span>;

<span class="hljs-keyword">const</span> reader = createReader(process.cwd(), keystaticConfig);

<span class="hljs-keyword">const</span> page = <span class="hljs-keyword">async</span> ({ params }: { params: { slug: <span class="hljs-built_in">string</span>; }; }) =&gt; {
    <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span> reader.collections.articles.read(params?.slug);
    <span class="hljs-keyword">if</span> (!article) <span class="hljs-keyword">return</span> notFound();

    <span class="hljs-keyword">return</span> (
        &lt;div className=<span class="hljs-string">"max-w-[900px] mx-auto py-8"</span>&gt;
            &lt;h1 className=<span class="hljs-string">"text-3xl font-bold"</span>&gt;{article.title}&lt;/h1&gt;

            {article.cover &amp;&amp;
                &lt;Image
                    width={<span class="hljs-number">300</span>}
                    height={<span class="hljs-number">300</span>}
                    alt=<span class="hljs-string">"Cover Image"</span>
                    src={article.cover + <span class="hljs-string">""</span>}
                    className=<span class="hljs-string">"!w-full mt-5 rounded-lg"</span>
                /&gt;
            }

            &lt;div className=<span class="hljs-string">"mt-6"</span>&gt;
                &lt;DocumentRenderer <span class="hljs-built_in">document</span>={<span class="hljs-keyword">await</span> article.text()} /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> page;
</code></pre>
<p>Now, a quick breakdown on what's happening in this code:</p>
<ul>
<li><p>We're creating a Keystatic Reader, which acts as our connection to the Keystatic content management system.</p>
</li>
<li><p>This code handles dynamic content pages. These pages are designed to display articles or content based on the slug provided in the URL. Slugs are typically a part of the URL used to identify specific pieces of content.</p>
</li>
<li><p>Inside the <code>page</code> function, we attempt to retrieve an article from the Keystatic collections based on the slug provided in the URL.</p>
</li>
<li><p>If no article is found with the given slug, the code returns a "not found" response, indicating that the requested content isn't available.</p>
</li>
<li><p>If an article is found, the code renders it on the web page. This includes displaying the article's title, cover image (if available), and text content.</p>
</li>
<li><p>The <code>DocumentRenderer</code> component is used to ensure that the article's text content is properly formatted and displayed.</p>
</li>
</ul>
<p>Now this is all we need to cover about working with Keystatic and displaying content in Nextjs marking the end of Part 2 of this series.</p>
<p>Resources:</p>
<p><a target="_blank" href="https://keystatic.com/">https://keystatic.com/</a></p>
<p><a target="_blank" href="https://nextjs.org/">https://nextjs.org/</a></p>
<p><a target="_blank" href="https://github.com/marville001/nextjs-keystatic-blog">https://github.com/marville001/nextjs-keystatic-blog</a></p>
<p>If you would like to see the complete app with styling, please leave a comment and I will share the link.</p>
<p><img src="https://media0.giphy.com/media/26u4lOMA8JKSnL9Uk/200.gif?cid=ecf05e47lkzqs2zrvjogrwnvy2ik7bmaramdech83d7akbtx&amp;ep=v1_gifs_search&amp;rid=200.gif&amp;ct=g" alt="SpongeBob gif. With a satisfied smile on his face and his eyes closed, Spongebob wipes his hands together in front of him, dust proofing from between his palms. Obviously a job well done." /></p>
<p>Keep coding :)</p>
<p>🤖</p>
]]></content:encoded></item><item><title><![CDATA[Create a blog website using NextJs and Keystatic - Setup (Part 1)]]></title><description><![CDATA[In the world of creating websites, it's like starting with a blank page and a burst of ideas. I took a little break recently from writing blogs, sort of on purpose, to figure out the best way to do things. Now, I've decided to take on a fun project: ...]]></description><link>https://blog.mmwangi.com/create-a-blog-website-using-nextjs-and-keystatic-setup-part-1</link><guid isPermaLink="true">https://blog.mmwangi.com/create-a-blog-website-using-nextjs-and-keystatic-setup-part-1</guid><category><![CDATA[nextjs 13.4]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[Keystatic]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Fri, 18 Aug 2023 17:00:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/LJ9KY8pIH3E/upload/b8de1d0b6aca103f5be98228a65ac3fb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the world of creating websites, it's like starting with a blank page and a burst of ideas. I took a little break recently from writing blogs, sort of on purpose, to figure out the best way to do things. Now, I've decided to take on a fun project: making a blog website. But don't worry, I'll guide you through it step by step, making sure we're all on the same page.</p>
<p>In this series of blog posts, I want to show you how to make your own blog site using Next.js and Keystatic. They're like the special tools we need to bring our ideas to life online. Think of it as crafting something cool with a digital toolkit!</p>
<p>In this first part, we'll start with the basics. We'll set things up, kind of like getting the foundation ready for a house. It might sound a bit technical, but I promise to explain it all in simple terms. We'll take it slow and steady, making sure we don't miss any important steps.</p>
<p>But wait, there's more to this adventure! We're not just stopping at the beginning. We're going to keep going until we've got our blog up and running for everyone to see. It's like putting the finishing touches on a masterpiece and then displaying it for the world to enjoy, thanks to a special place called Vercel.</p>
<p>As we move forward, we'll learn about designing our blog, adding cool features, and making it work really well. It's going to be a mix of creativity and technology, and I'm here to help you every step of the way.</p>
<p>So, let's jump right in and start with the very first chapter of our journey: getting things ready for our Next.js and Keystatic-powered blog. Get ready for a fun ride filled with learning and creating!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we dive into the exciting world of building your own blog website with Next.js and Keystatic, there are a couple of things you should be familiar with. Don't worry, I'll keep it simple!</p>
<ol>
<li><p>Basic Understanding of React: Having a grasp of the fundamentals of React, a popular JavaScript library for building user interfaces, will be really helpful. If you've played around with components, state, and props, you're on the right track.</p>
</li>
<li><p>Introduction to Next.js: It's good to have a bit of familiarity with Next.js, a framework that works with React and simplifies the process of building web applications. If you know how Next.js handles routing and server-side rendering, you'll be in a great position.</p>
</li>
</ol>
<p>If those prerequisites sound a bit intimidating, don't fret! I'll explain concepts along the way and provide references for you to brush up on if needed. Remember, this journey is about learning and growing. So, if you're ready to embark on this adventure of creating your own blog site, let's get started!</p>
<h2 id="heading-what-is-nextjs"><strong>What is Next.js?</strong></h2>
<p>Imagine Next.js as a super helper for creating websites. It's like a magic box filled with tools that make building websites easier. Instead of just showing plain pages, Next.js can make your pages load faster and look better. It's like making sure your guests at a party have a super comfy chair to sit on before they even arrive!</p>
<h2 id="heading-what-is-keystatic">What is Keystatic?</h2>
<p>Keystatic is a content management system (CMS) that works seamlessly with Next.js. Think of it as the engine that powers the content of your website. With Keystatic, you can easily manage and update your blog posts, images, and other content without diving into complex code. It helps you separate content creation from coding, making your life as a developer and content creator much easier.</p>
<h2 id="heading-why-use-nextjs-and-keystatic-to-create-a-blog-website">Why use Next.js and Keystatic to create a blog website?</h2>
<p>Choosing Next.js and Keystatic for your blog website comes with several advantages:</p>
<ul>
<li><p><strong>Faster Loading</strong>: Next.js's server-side rendering speeds up page load times, improving user experience and SEO.</p>
</li>
<li><p><strong>Efficient Development</strong>: Next.js simplifies complex tasks, letting you focus more on creating features and less on setup.</p>
</li>
<li><p><strong>Great User Experience</strong>: Faster-loading pages and smooth transitions create a better browsing experience for your readers.</p>
</li>
<li><p><strong>Easy Content Management</strong>: Keystatic's intuitive CMS interface empowers you to manage your blog content effortlessly.</p>
</li>
<li><p><strong>Flexibility</strong>: Next.js allows you to build static sites, server-rendered apps, or a mix of both, giving you flexibility in how you create your website.</p>
</li>
<li><p><strong>SEO Benefits</strong>: Server-side rendering and proper metadata handling in Next.js contribute to better search engine visibility.</p>
</li>
<li><p><strong>Community and Support</strong>: Both Next.js and Keystatic have active communities, ensuring you can find help and resources when needed.</p>
</li>
</ul>
<p>By combining the power of Next.js with the content management capabilities of Keystatic, you'll be equipped to create a blog website that's not only visually appealing but also high-performing and easy to manage. It's a dynamic duo that empowers you to bring your creative vision to life without getting lost in technical complexities. In the upcoming sections of this series, we'll explore how to set up and integrate these tools step by step.</p>
<h2 id="heading-nextjs-setup-with-tailwindcss">Next.Js Setup - with Tailwindcss</h2>
<p>Start by creating a new Next.js project if you don’t have one set up already.</p>
<pre><code class="lang-bash">npx create-next-app@latest
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692363280226/e9d72cbc-d5e3-47ca-b623-5688cdfd0e43.png" alt class="image--center mx-auto" /></p>
<p>As you can see from the above image, I have selected Yes for Tailwind CSS which we will use for our styling.</p>
<p>Next will be to enter your project directory and start the server by running the command <code>npm run dev</code> . This will start the Next.js project on http://localhost:3000.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692363820106/33a00159-d6e9-40b5-bdb5-9fdff16b1382.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-adding-keystatic-to-the-nextjs-project"><strong>Adding Keystatic to the Next.js project</strong></h2>
<p>NB - From <a target="_blank" href="https://keystatic.com/docs/installation-next-js">keystatic documentation</a>.</p>
<p>We're going to need to install a few packages to get Keystatic going.</p>
<p>Let's install two packages from npm:</p>
<pre><code class="lang-bash">npm install @keystatic/core @keystatic/next
</code></pre>
<h3 id="heading-creating-a-keystatic-config-file">Creating a Keystatic config file</h3>
<p>Keystatic needs a config file. This is where you can connect a project with a specific GitHub repository and define a content schema.</p>
<p>Let's create a file called <code>keystatic.config.ts</code> in the root of the project:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// keystatic.config.ts</span>
<span class="hljs-keyword">import</span> { config, fields, singleton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/core'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config({
  storage: {
    kind: <span class="hljs-string">'local'</span>,
  },
  singletons: {
    homepage: singleton({
      label: <span class="hljs-string">'Homepage'</span>,
      path: <span class="hljs-string">'src/content/_homepage'</span>,
      schema: {
        headline: fields.text({ label: <span class="hljs-string">'Headline'</span> }),
      },
    }),
  },
})
</code></pre>
<p>We export a config object wrapped in the <code>config</code> function imported from <code>@keystatic/core</code>.</p>
<p>For now, we set the <code>storage</code> strategy to <code>local</code>, and we create a “homepage” <code>singleton</code> which contains one text field: <code>headline</code>.</p>
<p>With that, we are done with all configuration Keystatic needs to start managing content.</p>
<p>Now, let's display the Keystatic Admin UI on our site!</p>
<h3 id="heading-adding-keystatic-admin-ui-pages">Adding Keystatic Admin UI pages</h3>
<p>The Keystatic Admin UI runs in NextJS' app directory.</p>
<p>In your <code>src/app</code> directory, we want every route within the <code>/keystatic</code> segment to become a Keystatic Admin UI route.</p>
<p>Create a <code>keystatic</code> folder in your <code>src/app</code> directory, and add the following files to help with our keystatic admin layout.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/keystatic/keystatic.ts</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { makePage } <span class="hljs-keyword">from</span> <span class="hljs-string">"@keystatic/next/ui/app"</span>;
<span class="hljs-keyword">import</span> config <span class="hljs-keyword">from</span> <span class="hljs-string">"../../keystatic.config"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> makePage(config);
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/keystatic/layout.tsx</span>

<span class="hljs-keyword">import</span> KeystaticApp <span class="hljs-keyword">from</span> <span class="hljs-string">"./keystatic"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html&gt;
      &lt;head /&gt;
      &lt;body&gt;
        &lt;KeystaticApp /&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<p>To ensure all routes in the keystatic segment work as expected, we can leverage Next.js' <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#optional-catch-all-segments"><strong>Optional Catch-all Segments</strong></a> to match file paths of any depth.</p>
<p>Let's create a new folder called <code>[[...params]]</code>, and add a <code>page.tsx</code> file with the following:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/keystatic/[[...params]]/page.tsx</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
</code></pre>
<p>Before we can actually start reading and writing content via the Keystatic Admin UI, we need to create some <code>API routes</code> for Keystatic.</p>
<h3 id="heading-adding-keystatic-api-routes">Adding Keystatic API Routes</h3>
<p>Create a new file at <code>app/api/keystatic/[...params]/route.ts</code></p>
<p>Once again, we use Next.js's dynamic route segments here.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/app/api/keystatic/[...params]/route.ts</span>

<span class="hljs-keyword">import</span> { makeRouteHandler } <span class="hljs-keyword">from</span> <span class="hljs-string">'@keystatic/next/route-handler'</span>;
<span class="hljs-keyword">import</span> config <span class="hljs-keyword">from</span> <span class="hljs-string">'../../../../../keystatic.config'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> { POST, GET } = makeRouteHandler({
  config,
});
</code></pre>
<p>We should be all set to go for our Keystatic Admin UI now.</p>
<p>Try and visit the <code>/keystatic</code> page in the browser one more time, and click on the “Homepage” singleton:</p>
<p><img src="https://keystatic.io/images/keystatic-docs/astro-keystatic-homepage.png" alt="Keystatic homepage singleton for Next.js demo" /></p>
<p>In our Keystatic config file, we have set the <code>storage</code> kind to <code>local</code>. For our <code>homepage</code> singleton, we set the <code>path</code> property to the following:</p>
<pre><code class="lang-typescript">path: <span class="hljs-string">'src/content/_homepage'</span>,
</code></pre>
<p>If you edit the Headline and click create then look in the <code>src</code> directory, a new <code>content</code> folder should have been created.</p>
<p>And with that, we are done with the base setup we need.</p>
<p>Resources:</p>
<p><a target="_blank" href="https://keystatic.com/">https://keystatic.com/</a></p>
<p><a target="_blank" href="https://nextjs.org/">https://nextjs.org/</a></p>
<p><a target="_blank" href="https://github.com/marville001/nextjs-keystatic-blog">https://github.com/marville001/nextjs-keystatic-blog</a></p>
<p>In the next part, we will check on displaying Keystatic content on the Next.js front-end.</p>
<p>That's all for part 1.</p>
<p><img src="https://media0.giphy.com/media/HwmDZaI4YEeZ2/200w.gif?cid=ecf05e47jdbp1mkutdwj6b66yji5ora8f6amttncsm23odwp&amp;ep=v1_gifs_search&amp;rid=200w.gif&amp;ct=g" alt="Video gif. A little girl in a swimsuit lies down on wet sand. Text, &quot;I take a nap right here.&quot;" /></p>
<p>Keep coding :)</p>
<p>🤖</p>
<p><a target="_blank" href="https://keystatic.com/docs/installation-next-js#keystatic-api-routes">  
</a></p>
]]></content:encoded></item><item><title><![CDATA[Boosting Next.js Performance: Turbocharge Your Website!]]></title><description><![CDATA[Welcome, fellow developers, to the high-speed highway of Next.js performance optimization! 🚀 If you're tired of watching your website lag behind in the slow lane, worry not! Today, we're diving headfirst into the world of Next.js performance, armed ...]]></description><link>https://blog.mmwangi.com/boosting-nextjs-performance-turbocharge-your-website</link><guid isPermaLink="true">https://blog.mmwangi.com/boosting-nextjs-performance-turbocharge-your-website</guid><category><![CDATA[Next.js]]></category><category><![CDATA[react js]]></category><category><![CDATA[Server side rendering]]></category><category><![CDATA[ssg]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Tue, 04 Jul 2023 21:01:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/jLwVAUtLOAQ/upload/3dfb0eba3c946a80ec75bb068f98b5c2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome, fellow developers, to the high-speed highway of Next.js performance optimization! 🚀 If you're tired of watching your website lag behind in the slow lane, worry not! Today, we're diving headfirst into the world of Next.js performance, armed with powerful tools, expert tips, and maybe even a few jokes along the way.</p>
<p>Remember, improving performance isn't just about satisfying impatient users—it's also about making search engines fall head over heels for your lightning-fast website. So buckle up, tighten your seat belts, and let's hit the pedal to the metal with some Next.js speed hacks!</p>
<h2 id="heading-what-is-nextjs">What is Next.Js?</h2>
<p>Next.js is a React framework that is widely recommended as a zero-configuration, single-command toolchain used for React projects. It serves as the fundamental building block for developing high-performance web applications.</p>
<p>To build user-friendly and superfast SEO-friendly, static websites, you will need the support of a robust framework for the unhindered functioning of the applications. Next.Js can build hybrid apps with statically generated and server-side rendered pages. Overall, it involves creating dynamic designs, interactive modules, and performance-based web applications for users.</p>
<p>Next.js offers an array of additional functionalities, including image optimization, a blend of static and server-side rendering, automatic code splitting, bundling, CSS optimization, JavaScript, and more. Nonetheless, even with such an optimized framework, it becomes essential to harness other dependable elements within this framework to ensure the scalability of your applications.</p>
<p>That's why understanding how to enhance Next.js performance is vital in creating top-notch apps for users and delivering them a captivating and immersive experience.</p>
<h2 id="heading-nextjs-speed-hacks">Next.Js speed hacks</h2>
<h3 id="heading-caching-is-a-piece-of-cake">Caching is a Piece of Cake</h3>
<p><a target="_blank" href="https://morioh.com/p/cd4e69f7828a"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686682911714/e5857bb0-cd22-4152-a294-fd3cfccf4cd0.png" alt class="image--center mx-auto" /></a></p>
<p>What's better than getting a slice of cake? Caching it! Implementing caching mechanisms like static site generation (SSG) or server-side rendering (SSR) can significantly boost your Next.js app's speed. Serve up pre-rendered pages to your visitors, and they'll be licking their fingers in delight!</p>
<p>Implementing caching can significantly improve the response time of your application while reducing the number of requests made to external services. It's an excellent strategy for optimizing the rendering of your app. In Next.js, caching header tags are typically included for static assets obtained from the /_next/static directory, such as static images, CSS, JavaScript, and other files.</p>
<p>When a request is made, images are dynamically optimized and stored in the &lt;distDir&gt;/cache/images directory. These optimized image files serve as concurrent requests until they expire.</p>
<p>If a cache file is requested after it has expired, it will be deleted. This means that you can generate a new optimized image for caching, ensuring that your application continues to benefit from efficient caching mechanisms.</p>
<h3 id="heading-optimize-those-images">Optimize Those Images</h3>
<p><a target="_blank" href="https://www.abetterlemonadestand.com/optimizing-images-for-web/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686683332700/c79cd329-ec27-40a0-94cc-93ab75d1e032.jpeg" alt class="image--center mx-auto" /></a></p>
<p>Images can be heavyweights in the world of web performance. Compress, resize, and lazy load your images to minimize the load on your user's browsers. By making your images light as a feather, you'll keep your website nimble and your users happy.</p>
<p>So how does Next.Js do this?</p>
<ul>
<li><p>Prioritize the images you want to load. It will load the images above the fold and then load them asynchronously while scrolling down. The Next.js picture device does this usually.</p>
</li>
<li><p>Serves the right image size in the desired format depending on the user’s bandwidth and resources.</p>
</li>
<li><p>Supports next-generation formats like WebP</p>
</li>
<li><p>Avoids cumulative layout shifts by using placeholders until the entire image loads</p>
</li>
<li><p>Adapts to responsive designs so images can scale or fit the size</p>
</li>
</ul>
<h3 id="heading-delay-loading-the-non-essential-scripts-until-it-gets-neutral"><strong>Delay loading the non-essential scripts until it gets neutral</strong></h3>
<p>In many cases, developers have no choice but to include third-party scripts for analytics and customer communication tools due to specific business requirements. However, the downside is that adding heavy scripts to a page can significantly slow down the user experience.</p>
<p>Therefore, it becomes crucial to have control over the loading of resources. This is where Next.js comes to the rescue with its Next/script feature. By utilizing Next/script, you can specify when the browser should fetch the relevant scripts, allowing you to optimize the performance of third-party scripts in your app. Let's take the example of Google Analytics.</p>
<p>Often, these third-party scripts heavily utilize the main thread's resources, resulting in the blocking of render-critical components. However, by using the next/script component in Next.js, you gain the ability to prioritize the loading of scripts. This way, you can ensure that these scripts don't hinder the rendering of important components. Additionally, when combined with a visual development platform like Builder, you can optimize JavaScript while maintaining flexibility in adding and managing third-party scripts.</p>
<p>By taking advantage of Next/script in Next.js, you can fine-tune the loading of third-party scripts, enhancing the performance and overall user experience of your application.</p>
<h3 id="heading-lazy-load-components">Lazy Load Components</h3>
<p>Why load everything at once when you can take it easy? Utilize lazy loading techniques to defer the loading of non-critical components until they're needed.</p>
<p>So, instead of serving everything for that page together, Next.js can support dynamic imports so you can split the code into small chunks and load whenever necessary. It also helps reduce the application size and improve your app performance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Boosting Next.js performance is crucial for turbocharging your website and delivering a seamless user experience. By implementing a variety of optimization techniques, such as code splitting, server-side rendering, and caching, you can significantly improve your website's speed and responsiveness. Additionally, leveraging advanced features like Next.js Image Optimization and API routes can further enhance performance and reduce load times.</p>
<p>Remember to monitor your website's performance regularly, analyze bottlenecks, and fine-tune your optimizations accordingly. By prioritizing performance and employing the best practices outlined in this blog and others, you can supercharge your Next.js website, delight your users, and stay ahead of the competition in today's fast-paced digital landscape.</p>
<p>That's all for now folks.</p>
<p>Happy coding</p>
<p>🤖</p>
]]></content:encoded></item><item><title><![CDATA[Next.js 13 and Docker: Unleashing Web Development Magic, One Container at a Time!]]></title><description><![CDATA[🚢 Ahoy, code adventurers!
🌟 Brace yourself for an exciting journey into the world of Next.js 13 and Docker! Welcome to our weekly blog, where we blend the magic of website building with the power of smart containers, all while having a boatload of ...]]></description><link>https://blog.mmwangi.com/nextjs-13-and-docker-unleashing-web-development-magic-one-container-at-a-time</link><guid isPermaLink="true">https://blog.mmwangi.com/nextjs-13-and-docker-unleashing-web-development-magic-one-container-at-a-time</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Sun, 28 May 2023 07:30:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Wgw0wwXMdk0/upload/a3cd4da70e2e21634b7048233c9045a1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>🚢 Ahoy, code adventurers!</p>
<p>🌟 Brace yourself for an exciting journey into the world of Next.js 13 and Docker! Welcome to our weekly blog, where we blend the magic of website building with the power of smart containers, all while having a boatload of fun! ⚡️</p>
<p>Similar to Dockerizing other applications, encapsulating your Next.js application on a docker container brings numerous advantages. Firstly, you get to ship the entire stack—not just your code, but also the operating system, specific versions of other languages or executables, and more. This means bidding farewell to the dreaded "works on my machine" syndrome.</p>
<p>But that's not all! Docker also empowers you to run multiple copies of your application, allowing for horizontal scaling. With the ease and cost-effectiveness of spinning up a docker container, scaling your Next.js app becomes a breeze, especially when paired with a container orchestrator like Kubernetes. The benefits of portability and scalability offered by Docker are game-changers for your Next.js applications.</p>
<p>And let's not forget about the caching challenge posed by Next.js applications that utilize server-side rendering and API routes. Since these features can't be cached on a Content Delivery Network (CDN), Dockerizing your Next.js app becomes a seamless solution. It enables easy deployment into a Kubernetes cluster or even serverless containers, opening up a world of possibilities.</p>
<p>So, get ready to explore the fascinating realm where Next.js 13 and Docker intersect. Join me each week as I uncover invaluable tips, tricks, and insights to take your web development adventures to new heights. Let's set sail and unlock the full potential of Next.js and Docker together! 🚀</p>
<h2 id="heading-key-requirements-for-building-a-docker-image">Key Requirements for Building a Docker Image</h2>
<p>To ensure a smooth creation of the Docker image, there are a few prerequisites that need to be met:</p>
<ol>
<li><p>Node.js and NPM must be installed on your system.</p>
</li>
<li><p>Docker needs to be installed as well.</p>
</li>
</ol>
<p>Once these requirements are fulfilled, we can proceed with creating the Next.js app.</p>
<h2 id="heading-creating-a-nextjs-app">Creating a Next.js app</h2>
<p>In this article, we will work with a basic next js app generated when you run the command:</p>
<pre><code class="lang-bash">npx create-next-app@latest nextjs-docker-app
</code></pre>
<p>Run the development server using the command <code>npm run dev</code> which should give an output that the server is running on <em>http://localhost:3000</em>. When you open your browser on the provided URL, you should have an output similar to the one below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685216446762/c5e7f758-0a60-414f-8a45-9c0921da84e3.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-writing-a-dockerfile">Writing a Dockerfile</h2>
<p>Before we begin, let us first define the terms Container and Image, and why we are building a Dockerfile.</p>
<p>An image, or a pre-built package containing the application code and its dependencies, is required to execute within a container. To construct an image, you'll require a <a target="_blank" href="https://blog.thereactivedeveloper.com/mastering-dockerfile-understanding-dockerfile-instructions-and-types">Dockerfile</a>, which is a set of instructions that instructs Docker how to build the image.</p>
<p><a target="_blank" href="https://blog.thereactivedeveloper.com/introduction-to-docker-compose-and-nodejs-and-beyond">Docker</a>, in a nutshell, allows developers to simply generate, distribute, and deploy images, resulting in faster development cycles and simpler application management.</p>
<p>With that stated, let's create a file named, "<a target="_blank" href="https://blog.thereactivedeveloper.com/mastering-dockerfile-understanding-dockerfile-instructions-and-types">Dockerfile</a>" in our root directory and paste the following content within it.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:<span class="hljs-number">16</span>-alpine
<span class="hljs-keyword">RUN</span><span class="bash"> mkdir -p /app</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm run build</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]</span>
</code></pre>
<p>Here, we defined a base image i.e. node:16-alpine.</p>
<p>What exactly does it do? It will download the <a target="_blank" href="https://hub.docker.com/_/node">node:16-alpine</a> image from the Docker Hub (with Node. js, npm, and other necessary tools pre-installed).</p>
<p>Afterward, as per the instruction, it creates a directory and sets it as a working directory, then copies the application files into the working directory. The “RUN npm install” and “RUN npm run build” lines install dependencies &amp; build the application. Finally, we expose port 3000, and start the application using the command "npm start".</p>
<p>This was our configuration stored inside the Dockerfile.</p>
<p>Now, let’s build an image using this.</p>
<pre><code class="lang-bash">docker build -t nextjs-docker-app ./
</code></pre>
<p>We tagged(or named) this image as "nextjs-docker-app" and then specified the directory where the Dockerfile is located, which is the root directory for us.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685253708566/61cd5bdc-9bbe-498a-8bb1-3b482971bbf7.png" alt class="image--center mx-auto" /></p>
<p>As you can see from the logs, it is retrieving the base image and then executing everything specified in the Dockerfile.</p>
<p>After the process finishes, it will generate a docker image, which you can see using the "docker images" command.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685253967027/d08f558b-30ab-40b1-9165-72f7c8356081.png" alt class="image--center mx-auto" /></p>
<p>It's 894MB in size and in the next section, we’ll see how you can reduce this number drastically. </p>
<p>To run this image within a container(specifying the port as 3000) use the following command.</p>
<pre><code class="lang-bash">docker run -d -p 3000:3000 nextjs-docker-app
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685253839006/d4d69fc2-8b46-4089-8633-20a375a15725.png" alt class="image--center mx-auto" /></p>
<p>You can now go to localhost:3000 and see your app running, but this time from the Docker container.</p>
<p>But wait, our docker image is not optimized 🤨.</p>
<h2 id="heading-optimizing-the-docker-image">Optimizing the Docker Image</h2>
<p>Previously, we created a simple Dockerfile and provided some basic instructions to create an image that can be run inside a container.</p>
<p>However, there is room for further optimization as the current image size is 894MB which is not ideal for production apps. There are various methods to optimize the image size, and we will focus on a simple approach based on the factors listed below.</p>
<ol>
<li><p>Pick a different smaller base image(it’s not always the case): You can use a smaller base image to reduce the image size.</p>
</li>
<li><p>Combine commands: You may combine the “RUN npm install” and “RUN npm run build” instructions into a single ”RUN npm ci —quiet &amp;&amp; npm run build” command. This reduces the number of layers in the image and its size.</p>
</li>
<li><p>Use multi-stage builds: You can divide your Dockerfile into two stages, with the first stage building your app and in the second stage you can copy only the files required. This will reduce redundant files and environments that we created in the first stage.</p>
</li>
</ol>
<p>Here, we will primarily use multi-stage builds to demonstrate how we can easily reduce the size by roughly 100 MB.</p>
<p>Let's proceed with the optimization process by replacing the contents of the existing Dockerfile with the following instructions.</p>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># Build Stage</span>
<span class="hljs-keyword">FROM</span> node:<span class="hljs-number">16</span>-alpine AS BUILD_IMAGE
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> package*.json ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm ci</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm run build</span>


<span class="hljs-comment"># Production Stage</span>
<span class="hljs-keyword">FROM</span> node:<span class="hljs-number">16</span>-alpine AS PRODUCTION_STAGE
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=BUILD_IMAGE /app/package*.json ./</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=BUILD_IMAGE /app/.next ./.next</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=BUILD_IMAGE /app/public ./public</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=BUILD_IMAGE /app/node_modules ./node_modules</span>
<span class="hljs-keyword">ENV</span> NODE_ENV=production
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]</span>
</code></pre>
<p>We have divided our Dockerfile file into two sections i.e. "Build Stage" and "Production Stage". And the commands are pretty self-explanatory and straightforward.</p>
<p>For the build stage, the commands are similar to the Dockerfile we created earlier. On the other hand, in the production stage, we are just copying the files that we need from the build stage and running the app.</p>
<p>Let’s build a new app with the new Dockerfile and name this image "nextjs-docker-app-2"</p>
<pre><code class="lang-bash">docker build -t nextjs-docker-app-2 .
</code></pre>
<p>And as you can see from the command "docker images", the second image saved around 791MB.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685254346541/83c01f87-f6e3-4920-a5f9-a16680b59222.png" alt class="image--center mx-auto" /></p>
<p>You can run this image by running the command "docker run -p 3000:3000 nextjs-docker-app-2" as well, and you will get the app on the browser.</p>
<h2 id="heading-taking-docker-image-optimization-to-the-next-level">Taking Docker Image Optimization to the Next Level</h2>
<p>As we can see, even after optimizing images with the help of multi-stage builds, we don't see significant image optimization because smaller Docker images are easier to deploy and scale. This is why we will be exploring other ways to further optimize our image size.</p>
<p>For that, create or update "next.config.js" file in the root directory to contain the below code.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">/**
* <span class="hljs-doctag">@type <span class="hljs-type">{import('next').NextConfig}</span></span>
*/</span>

<span class="hljs-keyword">const</span> nextConfig = {
   <span class="hljs-attr">experimental</span>: {
       <span class="hljs-attr">outputStandalone</span>: <span class="hljs-literal">true</span>,
   }
}

<span class="hljs-built_in">module</span>.exports = nextConfig
</code></pre>
<p>According to the <a target="_blank" href="https://nextjs.org/docs/advanced-features/output-file-tracing">documentation</a>, it will create a folder at “.next/standalone” which can then be deployed on its own without installing “node_modules”. It is also one of the most effective methods for optimizing the docker file. You can learn more about it <a target="_blank" href="https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files">here</a>.</p>
<p>Let's modify the Dockerfile now.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>-alpine as builder
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /my-space</span>

<span class="hljs-keyword">COPY</span><span class="bash"> package.json package-lock.json ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm ci</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm run build</span>

<span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>-alpine as runner
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /my-space</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /my-space/package.json .</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /my-space/package-lock.json .</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /my-space/next.config.js ./</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /my-space/public ./public</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /my-space/.next/standalone ./</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=builder /my-space/.next/static ./.next/static</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]</span>
</code></pre>
<p>The code in this section is mostly identical to the Dockerfile we created earlier using a multi-stage build. </p>
<p>As you can see, we did not use node_modules here, but rather the standalone folder, which will optimize the image to a greater extent. </p>
<p>Let’s build a new app with the new Dockerfile and name this image "nextjs-docker-app-3".</p>
<pre><code class="lang-bash">docker build -t nextjs-docker-app-3 ./
</code></pre>
<p>The resulting image size has now been reduced to 203MB.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685255022532/cf05eb75-04dd-4bdb-90a2-d07a31cf9b0e.png" alt class="image--center mx-auto" /></p>
<p>Now that's impressive. We can have a faster deployment and enhanced scalability 🥳.</p>
<h2 id="heading-what-really-matters-for-docker-image-disk-usage">What Really Matters for Docker Image Disk Usage</h2>
<p>In the earlier section on optimizing Docker images, we explored many aspects that might influence image size, such as using a smaller base image. However, some sources, such as <a target="_blank" href="https://semaphoreci.com/blog/2018/03/14/docker-image-size.html">Semaphore</a>, claim that the size of the base image is irrelevant in some cases.</p>
<p>Instead of the size of the base image, the size of frequently changing layers is the most important factor influencing disk usage. Because Docker images are composed of layers that may be reused by other images, the link between size and disk usage is not always clear.</p>
<p>Two images with the same layers, for example, might have drastically different disk consumption if one of the layers changes often. As a result, shrinking the base image may be ineffective in saving disc space and may restrict functionality.</p>
<p>If you wish to go more into the topic, you may do so <a target="_blank" href="https://semaphoreci.com/blog/2018/03/14/docker-image-size.html">here</a>.</p>
<h2 id="heading-when-to-consider-docker">When to Consider Docker?</h2>
<p>Docker, as we've seen, is a great tool for managing software dependencies and providing consistent environments.</p>
<p>Knowing when to use Docker and when to create a Docker image is crucial in achieving the benefits of this platform.</p>
<p>Docker is ideal for:</p>
<ol>
<li><p>An Isolated environment (for creating and testing apps)</p>
</li>
<li><p>Deployment purposes</p>
</li>
<li><p>Scalability</p>
</li>
<li><p>Continuous Integration and Deployment (CI/CD)</p>
</li>
</ol>
<p>It goes without saying that if you're using Docker, you'll need Docker images as well.</p>
<p>So, whether you require an isolated environment, want to deploy apps reliably and consistently, or want to ensure consistency across different environments, Docker can help.</p>
<p>That's all for now folks.</p>
<p>Happy coding</p>
<p>:)</p>
]]></content:encoded></item><item><title><![CDATA[Next.js 13: The Future of Web Development]]></title><description><![CDATA[The web development landscape has seen many frameworks come and go over the years, but Next.js has stood the test of time. With its latest release, Next.js 13, the framework has taken a major leap forward in terms of performance, developer experience...]]></description><link>https://blog.mmwangi.com/nextjs-13-the-future-of-web-development</link><guid isPermaLink="true">https://blog.mmwangi.com/nextjs-13-the-future-of-web-development</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Sat, 13 May 2023 05:58:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/w7ZyuGYNpRQ/upload/50f90b13a37810e4e2596e5b872a4650.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The web development landscape has seen many frameworks come and go over the years, but <a target="_blank" href="https://nextjs.org/">Next.js</a> has stood the test of time. With its latest release, Next.js 13, the framework has taken a major leap forward in terms of performance, developer experience, and new features. In this blog post, we'll explore what Next.js 13 has to offer and why you should learn it.</p>
<h1 id="heading-what-is-nextjs">What is Next.js?</h1>
<p>Before we dive into Next.js 13, let's take a step back and understand what Next.js is. Next.js is a React-based framework for building server-side rendered and statically generated web applications. It was created by Vercel, the company behind the popular Jamstack platform, and has gained a significant following among developers in recent years.</p>
<h1 id="heading-whats-new-in-nextjs-13">What's new in Next.js 13?</h1>
<p>Next.js 13 brings a lot of new features and improvements to the table. Here are some of the most noteworthy ones:</p>
<ul>
<li><h2 id="heading-server-components">Server Components</h2>
</li>
</ul>
<p>Server components are a new feature in Next.js 13 that allow developers to write server-side code directly within their React components. This can make it easier to create highly dynamic and interactive web applications, as well as improve performance by reducing the amount of data that needs to be sent to the client. With server components, developers can also create reusable server-side logic that can be shared across components.</p>
<ul>
<li><h2 id="heading-incremental-static-regeneration-isr">Incremental Static Regeneration (ISR)</h2>
</li>
</ul>
<p>Next.js 13 introduces Incremental Static Regeneration (ISR), which allows pages to be re-generated on demand, rather than on every request. This can significantly reduce load times and improve the overall user experience. ISR is particularly useful for sites with large amounts of data that don't change frequently, such as e-commerce sites, news sites, or blogs.</p>
<ul>
<li><h2 id="heading-improved-developer-experience">Improved Developer Experience</h2>
</li>
</ul>
<p>Next.js 13 has made several improvements to its developer experience, making it easier and more enjoyable to work with. For example, it has improved its integration with popular IDEs like VS Code, making it easier to develop and debug Next.js applications. Additionally, it has added new features like automatic image optimization, which can help to improve performance by reducing image file sizes.</p>
<h1 id="heading-why-learn-nextjs-13">Why learn Next.js 13?</h1>
<p>Next.js 13 is a highly popular and in-demand framework, so mastering it can help to improve your career prospects. Additionally, its support for server components and ISR makes it a powerful tool for building highly dynamic and performant web applications. Finally, its developer experience enhancements make it easier and more enjoyable to work with, making it a great choice for developers of all levels.</p>
<p>But beyond the practical benefits of learning Next.js 13, there are also some broader reasons why it's worth investing your time and energy into this framework.</p>
<ul>
<li><h2 id="heading-future-proofing-your-skills">Future-Proofing Your Skills</h2>
</li>
</ul>
<p>The web development landscape is constantly evolving, and it's important to stay up-to-date with the latest tools and technologies. By learning Next.js 13, you'll be future-proofing your skills and ensuring that you're equipped to take on whatever challenges the web throws your way.</p>
<ul>
<li><h2 id="heading-community-and-support">Community and Support</h2>
</li>
</ul>
<p>Next.js has a large and active community of developers who are constantly sharing their knowledge and expertise. By becoming a part of this community, you'll have access to a wealth of resources and support that can help you to grow as a developer.</p>
<ul>
<li><h2 id="heading-the-joy-of-learning">The Joy of Learning</h2>
</li>
</ul>
<p>Finally, learning Next.js 13 can be a deeply satisfying and enjoyable experience. There's something incredibly rewarding about mastering a new tool or technology and using it to create something amazing. So, even if you don't have any practical reasons for learning Next.js 13, the joy of learning itself is a great reason to dive in.</p>
<h1 id="heading-my-thoughts">My Thoughts</h1>
<p>Next.js 13 is a significant step forward for web development.</p>
<p>Server components and Incremental Static Regeneration are two features that can greatly improve the performance and flexibility of web applications. By allowing developers to write server-side code within their React components, server components can simplify the development process and create more dynamic applications. Meanwhile, Incremental Static Regeneration can greatly reduce load times and improve user experience, particularly for sites with large amounts of data.</p>
<p>Overall, I believe that Next.js 13 is a framework worth learning for any web developer who wants to stay up-to-date with the latest trends and tools in the industry. Its support for server-side rendering and static site generation, combined with its ease of use and community support, make it a powerful and versatile tool for building high-quality web applications.</p>
<p>That's all on this one. More articles on the way about Next.js 13</p>
<p>Happy coding :)</p>
<p>🤖</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to Docker Compose and Node.js and beyond 😀]]></title><description><![CDATA[Docker Compose is a tool for defining and running multi-container Docker applications. It provides a way to define the services that make up your application, their dependencies, and how they interact with each other. This makes it easier to manage a...]]></description><link>https://blog.mmwangi.com/introduction-to-docker-compose-and-nodejs-and-beyond</link><guid isPermaLink="true">https://blog.mmwangi.com/introduction-to-docker-compose-and-nodejs-and-beyond</guid><category><![CDATA[Docker]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[Docker compose]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Tue, 18 Apr 2023 20:45:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681838424211/0c77c09e-8bbc-43d9-82fe-164bbe3ffc09.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Docker Compose is a tool for defining and running multi-container Docker applications. It provides a way to define the services that make up your application, their dependencies, and how they interact with each other. This makes it easier to manage and scale complex applications.</p>
<p>In this article, we'll explore how to use Docker Compose with a basic Node.js application. We'll cover the basics of Docker Compose, show you how to define a simple application, and demonstrate how to run it using Docker Compose. Then we will check a comprehensive docker-compose.yml file configuration and explain it.</p>
<p>To learn the basics about docker, view my list of introductory articles on the topic <a target="_blank" href="https://blog.thereactivedeveloper.com/">here</a>.</p>
<h1 id="heading-prerequisites"><strong>Prerequisites.</strong></h1>
<p>Before we get started, you'll need the following:</p>
<ul>
<li><p>Docker installed on your machine</p>
</li>
<li><p>Basic knowledge of Node.js</p>
</li>
<li><p>Basics about Docker and Dockerfile</p>
</li>
</ul>
<h1 id="heading-step-1-set-up-your-nodejs-application"><strong>Step 1: Set Up Your Node.js Application.</strong></h1>
<p>First, let's create a basic Node.js application. Create a new folder on your computer called "dockerapp", and initialize a new Node.js project inside it using the command <code>npm init -y</code>. This will create a <code>package.json</code> file for your project. Then install the express package using the command <code>npm install express.</code></p>
<p>Create a new file called <code>index.js</code> in your project directory and add the following code to it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);

<span class="hljs-keyword">const</span> app = express();

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Hello World!'</span>);
});

<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>This code sets up an Express.js application that listens for HTTP requests on port 3000 and responds with "Hello World!" when accessed.</p>
<h1 id="heading-step-2-create-a-dockerfile"><strong>Step 2: Create a Dockerfile.</strong></h1>
<p>Next, we'll create a Dockerfile that describes how to build our Node.js application. Create a new file in the "dockerapp" folder called "Dockerfile", and add the following code:</p>
<pre><code class="lang-javascript">FROM node:<span class="hljs-number">14</span>-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ <span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span> ]
</code></pre>
<p>This Dockerfile starts with a Node.js image, sets the working directory to "/app", copies the package.json and package-lock.json files into the container, installs the dependencies using npm, copies the rest of the files into the container, and starts the application using the <code>npm start</code> command.</p>
<h1 id="heading-step-3-define-a-docker-compose-file"><strong>Step 3: Define a Docker Compose File.</strong></h1>
<p>Now, let's define a Docker Compose file that describes how to run our Node.js application. Create a new file in the "dockerapp" folder called "docker-compose.yml", and add the following code:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">dockerapp:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
</code></pre>
<p>This Docker Compose file defines a service called "dockerapp" that builds the Docker image using the Dockerfile in the current directory and maps port 3000 from the container to port 3000 on the host machine.</p>
<h1 id="heading-step-4-run-your-application-with-docker-compose"><strong>Step 4: Run Your Application with Docker Compose.</strong></h1>
<p>Finally, let's run our Node.js application using Docker Compose. Open a terminal window, navigate to the "dockerapp" folder, and run the following command:</p>
<pre><code class="lang-bash">docker-compose up
</code></pre>
<p>This command builds the Docker image, starts the container, and maps the ports as defined in the Docker Compose file. You should see the output of the application in the terminal window, which should look something like this:</p>
<pre><code class="lang-bash">~ Server running at http://0.0.0.0:3000/
</code></pre>
<h1 id="heading-docker-compose-beyond-just-building-and-running-an-expressjs-application">Docker Compose beyond just building and running an Express.js application.</h1>
<p>One common use case for Docker Compose is to set up a development environment for a multi-container application. You can define each service in your application (such as a database, message queue, or API server) in a separate Dockerfile, and then use Docker Compose to start all of these services together in a development environment. This can help to simplify the development process and make it easier to debug issues that arise.</p>
<p>Another use case for Docker Compose is to set up a production environment for a multi-container application. In this case, you would define the services that make up your application in a <code>docker-compose.yml</code> file and use Docker Compose to deploy the application to a production environment. This can help to ensure that the application is running consistently across multiple hosts and can be easily scaled up or down as needed.</p>
<p>In addition to starting and stopping services, Docker Compose also provides other useful features, such as:</p>
<ul>
<li><p>Networking: Docker Compose automatically creates a network for your application and ensures that each service can communicate with the others.</p>
</li>
<li><p>Environment variables: You can define environment variables for your services in the <code>docker-compose.yml</code> file, making it easy to configure your application for different environments (such as development, staging, or production).</p>
</li>
<li><p>Volume management: Docker Compose allows you to define volumes for your services, which can be used to persist data between container restarts.</p>
</li>
<li><p>Health checks: You can define health checks for your services in the <code>docker-compose.yml</code> file, allowing Docker Compose to monitor the health of your application and automatically restart services if they fail.</p>
</li>
</ul>
<p>Overall, Docker Compose is a powerful tool for defining, building and deploying multi-container Docker applications. It can simplify the development process and help to ensure that your application is running consistently across different environments.</p>
<h1 id="heading-comprehensive-docker-compose-file-example">Comprehensive Docker Compose file example</h1>
<p>Here's an example of a comprehensive Docker Compose file that sets up a multi-container application consisting of a Node.js API server, a MySQL database, and a Redis message queue:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3'</span>

<span class="hljs-attr">services:</span>
  <span class="hljs-attr">api:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./api</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">DB_HOST:</span> <span class="hljs-string">db</span>
      <span class="hljs-attr">REDIS_HOST:</span> <span class="hljs-string">redis</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">db</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">redis</span>

  <span class="hljs-attr">db:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">example</span>
      <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">myapp</span>
      <span class="hljs-attr">MYSQL_USER:</span> <span class="hljs-string">myapp</span>
      <span class="hljs-attr">MYSQL_PASSWORD:</span> <span class="hljs-string">example</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3306:3306"</span>

  <span class="hljs-attr">redis:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">redis:6.2</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"6379:6379"</span>
</code></pre>
<p>In this example, we define three services:</p>
<ol>
<li><p><code>api</code>: This service builds a Docker image for a Node.js API server using the <code>./api</code> directory as the build context. It exposes port 3000 and sets environment variables for the database and Redis hostnames. It depends on the <code>db</code> and <code>redis</code> services.</p>
</li>
<li><p><code>db</code>: This service uses the <code>mysql:5.7</code> image to provide a MySQL database. It sets environment variables for the root password, database name, and user credentials. It exposes port 3306.</p>
</li>
<li><p><code>redis</code>: This service uses the <code>redis:6.2</code> image to provide a Redis message queue. It exposes port 6379.</p>
</li>
</ol>
<p>By using Docker Compose, we can start all of these services together with a single command:</p>
<pre><code class="lang-bash">docker-compose up
</code></pre>
<p>This will build the <code>api</code> Docker image and start all three services. We can then access the API server by visiting <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a> in a web browser.</p>
<h1 id="heading-conclusion">Conclusion.</h1>
<p>By defining our services in a <code>docker-compose.yml</code> file, we can easily deploy this application to other environments (such as a staging or production server) by running the same command. We can also take advantage of other Docker Compose features, such as volume management and health checks, to ensure that our application is running smoothly.</p>
<p>That's all friends.</p>
<p>Keep coding 😀.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Dockerfile: Understanding Dockerfile Instructions and Types]]></title><description><![CDATA[Dockerfile is an essential tool for building Docker images. It's a simple text file that contains all the instructions needed to build a Docker image. With Dockerfile, you can define the base image, add your application code, specify the dependencies...]]></description><link>https://blog.mmwangi.com/mastering-dockerfile-understanding-dockerfile-instructions-and-types</link><guid isPermaLink="true">https://blog.mmwangi.com/mastering-dockerfile-understanding-dockerfile-instructions-and-types</guid><category><![CDATA[Docker]]></category><category><![CDATA[Dockerfile]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Tue, 18 Apr 2023 19:30:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681836393596/8b81115f-f3a8-482b-bb85-60d126fe57e7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dockerfile is an essential tool for building Docker images. It's a simple text file that contains all the instructions needed to build a Docker image. With Dockerfile, you can define the base image, add your application code, specify the dependencies, and configure the environment.</p>
<p>Using Dockerfile, you can easily automate the building of your Docker images, making it easier to deploy your application across different environments. This helps to ensure consistency and reliability in your application deployment.</p>
<p>Dockerfile also provides a way to version control your images, making it easier to manage changes and track updates. This allows you to keep track of the changes made to your application and ensures that everyone on your team is working with the same version.</p>
<p>With Dockerfile, you can also optimize the size of your images by removing unnecessary dependencies, reducing the time it takes to build and deploy your application. This makes Dockerfile a powerful tool for containerization and DevOps.</p>
<p>Overall, Dockerfile is an essential tool for building, deploying, and managing Docker images. With its simplicity and flexibility, it's a must-have for any developer looking to containerize their application and streamline their deployment process.</p>
<p>Let's explore the different types of Dockerfile instructions and how they work together to build a Docker image. By understanding these Dockerfile instructions, you can optimize your Docker image-building process and streamline your application deployment workflow.</p>
<p>Here are the main types of Dockerfile instructions:</p>
<ol>
<li><p>FROM: Specifies the base image to be used for the container. Every Dockerfile starts with a FROM instruction.</p>
</li>
<li><p>RUN: Executes a command during the build process of the Docker image.</p>
</li>
<li><p>COPY: Copies files or directories from the build context (the folder where the Dockerfile is located) to the container.</p>
</li>
<li><p>ADD: Similar to COPY, but it also supports downloading files from URLs and extracting tar archives.</p>
</li>
<li><p>WORKDIR: Sets the working directory for subsequent instructions.</p>
</li>
<li><p>ENV: Sets environment variables inside the container.</p>
</li>
<li><p>EXPOSE: Informs Docker that the container will listen on the specified network ports at runtime.</p>
</li>
<li><p>CMD: Specifies the command to be run when the container starts.</p>
</li>
<li><p>ENTRYPOINT: Similar to CMD, but it specifies the command to be run when the container starts as an executable.</p>
</li>
<li><p>VOLUME: Creates a mount point in the container for external volumes.</p>
</li>
</ol>
<p>These are the main types of instructions you'll encounter in a Dockerfile. Each instruction plays a specific role in building and configuring the Docker image, and understanding them is essential to creating effective Dockerfiles.</p>
<p><strong>#docker</strong> <strong>#dockerfile</strong> <strong>#containerization</strong> <strong>#devops</strong></p>
]]></content:encoded></item><item><title><![CDATA[Form Handling in React.Js]]></title><description><![CDATA[With any application, handling forms is a crucial part as we need to allow users to input and submit various information for processing. The normal way of dealing with forms in HTML such as using text inputs, checkboxes, selects, radio buttons, and s...]]></description><link>https://blog.mmwangi.com/form-handling-in-reactjs</link><guid isPermaLink="true">https://blog.mmwangi.com/form-handling-in-reactjs</guid><category><![CDATA[React]]></category><category><![CDATA[forms]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[useState hook]]></category><category><![CDATA[useState]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Fri, 06 Jan 2023 15:00:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671530982728/S26DrwG5d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>With any application, handling forms is a crucial part as we need to allow users to input and submit various information for processing. The normal way of dealing with forms in HTML such as using text inputs, checkboxes, selects, radio buttons, and so on remains true even with React.Js.</p>
<p>In React, you can either choose to allow the browser to handle most of the form elements and collect data through <a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-handle-dom-and-window-events-with-react">React change events</a>, or you can use React to fully control the elements by setting and updating the input value directly. The first approach is called an uncontrolled component because React is not setting the value. The second approach is called a controlled component because React is actively updating the input.</p>
<p>In this article, we will check the two ways of handling forms in a React.Js application, how to submit a form (e.g. callback handler), and how to reset a form (e.g. after submission). By the end of this tutorial, you’ll be able to make a variety of forms using text inputs, checkboxes, select lists, and more.</p>
<h1 id="heading-prerequisite">Prerequisite</h1>
<ul>
<li><p>Have a development environment running Node.js</p>
</li>
<li><p>A React development environment set up with Create React App.</p>
</li>
<li><p>Basic knowledge of React such as how to manage state using <code>useState</code>, how to create components, etc.</p>
</li>
<li><p>You will also need a basic knowledge of JavaScript and HTML. We will also be using <a target="_blank" href="https://tailwindcss.com/">Tailwind C</a>SS for our styling and basic knowledge of the framework would be beneficial. However, you don't need to know Tailwind CSS as all the styling is provided.</p>
</li>
<li><p>Click <a target="_blank" href="https://github.com/marville001/form-handling-react/tree/starter-files">Here</a> to get the starter code. The code to the complete demo used in this article is provided at the end of the article.</p>
</li>
</ul>
<h2 id="heading-react-form-by-example"><strong>REACT FORM BY EXAMPLE</strong></h2>
<p>A common example of a form in various web applications is a login form where we capture both the email and password of the user we want to authenticate. A functional representation of such a form is as shown below</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Form = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>  <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Form;
</code></pre>
<p>If you click submit button, the form will reload. This is the default behavior of a form that we should prevent in our form. We need to handle the <code>submit</code> event inside the component</p>
<p>To handle the event, we’ll add an event handler to the <code>&lt;form&gt;</code> element, not the <code>&lt;button&gt;</code>. Create a function called <code>handleSubmit</code> that will take the <code>SyntheticEvent</code> as an argument. The<code>SyntheticEvent</code> is a wrapper around the standard <code>Event</code> object and contains the same interface. Call <code>.preventDefault</code> to stop the page from submitting the form then trigger an <code>alert</code> to show that the form was submitted:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Form = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        alert(<span class="hljs-string">"You have submitted the form."</span>);
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    Email
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    Password
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>  <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Form;
</code></pre>
<h2 id="heading-collecting-form-data-using-controlled-components">Collecting Form Data Using Controlled Components</h2>
<p>In the form above, we are rendering a simple form having two inputs one for email and the other for password. Nothing special. It is just like our regular HTML input. But to handle this input in React, we will need to understand the concept of a controlled input.</p>
<h3 id="heading-uncontrolled-and-controlled-input"><strong>Uncontrolled and Controlled Input</strong></h3>
<p>In a React application, an "uncontrolled input" is an input field that is not associated with a React component state. This means that the value of the input is not managed by the React component, and the component does not have direct access to the value of the input.</p>
<p>On the other hand, a "controlled input" is an input field that is associated with a React component state. The value of the input is managed by the React component, and the component has direct access to the value of the input. This means that the component can programmatically control the value of the input, as well as respond to changes in the input value.</p>
<p>We will use the controlled way to handle the input's state. The benefit of using controlled input is that we are making the component state the single source of truth for the inputs. All we have to do is declare a <code>state</code> object where data will live.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>) <span class="hljs-comment">// Set default value to ""</span>
</code></pre>
<p>Now, for us to make the input field a controlled input, we assigned the state variable (which contains a default empty string) to the <code>value</code> prop.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
</code></pre>
<p>After adding the value prop to input and assigning it to the email value from the state, if you try to write anything in the email text field, nothing will happen. This is because the <code>value</code> prop is assigned a state variable whose value is set to an empty string. And this is being forced on the input.</p>
<p>This is good because we now have total control over the input state. Let’s go ahead and update it. Update the code to include an <code>onChange</code> event handler.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleChange = <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    setEmail(e.target.value)
  }
...

&lt;input className=<span class="hljs-string">"form-input"</span> value={email} onChange={handleChange} id=<span class="hljs-string">"email"</span> type=<span class="hljs-string">"text"</span> /&gt;
</code></pre>
<p>React needs an <code>onChange</code> handler to keep track of any changes in the field. Anytime you write something in the input field, this <code>onChange</code> event will trigger and then call its <code>handleChange</code> function that will re-render the state using <code>setEmail</code> function.</p>
<p>At this point, we have a controlled email input field where its state is being managed by its component.</p>
<h2 id="heading-handling-multiple-inputs">Handling Multiple Inputs</h2>
<p>In reality, you’ll be working with multiple input fields in your React application. Our example form has two inputs for email and password. In this scenario, we will make a simple adjustment not only to the handler function but also to the <code>input</code> element and the state.</p>
<p>We could decide to set up another <code>useState</code> Hook for the password input. Then go ahead and assign its state variable to the <code>value</code> prop. But this approach will require us to define another handler function to update the input state.</p>
<p>When we need to handle multiple inputs, we don’t want to make a new onChange handler function for each input. Therefore, we want to make a function that can set all values.</p>
<p>We can do that as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [state, setState] = useState({
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
  })

<span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>)=&gt;</span> {
    setState({
        ...state,  
        [e.target.name]: e.target.value
    });
}
</code></pre>
<p>NB: Our form elements must have a name property with a value matching the key for the elements state. For example, the email input must have <code>name="email"</code> since we are using the key <code>email</code> on the state to store the value for that input and the password input must have <code>name="password"</code>.</p>
<p>Our input will change to be:</p>
<pre><code class="lang-xml">...
# Email Input
<span class="hljs-tag">&lt;<span class="hljs-name">input</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
    <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
    <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{state.email}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
/&gt;</span>

...
# Password Input
<span class="hljs-tag">&lt;<span class="hljs-name">input</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
    <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
    <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{state.password}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
/&gt;</span>
</code></pre>
<p>What is happening?</p>
<p>First, you will notice a significant change in the code. We started by modifying the <code>useState</code> Hook to include an additional input data. From there, we have access to the email and password through <code>state.email</code>and <code>state.password</code>as used in the <code>value</code> prop of their respective <code>input</code> element.</p>
<p>In these <code>input</code> elements, we’ve added a <code>name</code> prop that holds also their respective state name (i.e <code>email</code>and <code>password</code>). This is very important.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> Form = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [state, setState] = useState({
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
    });

    <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        setState(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> ({
            ...prev,
            [e.target.name]: e.target.value,
        }));
    };
    <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        event.preventDefault();
        alert(<span class="hljs-string">"You have submitted the form."</span>);
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    Email
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{state.email}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    Password
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{state.password}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Form;
</code></pre>
<p>Now, let’s focus on the <code>handleChange</code> function. Here, we are using the <code>setState</code> function to update the inputs state.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>)=&gt;</span> {
    setState({
        ...state,  
        [e.target.name]: e.target.value
    });
}
</code></pre>
<p>In this function, we are simply assigning to the element that is being targeted (through <code>[</code><a target="_blank" href="http://e.target.name"><code>e.target.name</code></a><code>]</code>) their corresponding values.</p>
<p>Still on the <code>handleChange</code> function. Anytime we group related data as we have it in the state variable, the state returned by the <code>useState</code> hook is not merged with that of the update passed to it. In other words, the <code>useState</code> Hook doesn’t merge the old and new state. Instead, it overrides the entire state with that of the current. So to avoid this scenario, we merge them by spreading the entire state object using the three dots before the state and overriding the part of it.</p>
<p>Now that you know how the control field works in React, adding any other input fields to a form will be a piece of cake. We need to update the state object to include the property for the new input, add the input, eg <code>textarea</code> to our form and add the name, value, and onChange properties to it similar to how we added them to the email and password input. Let's check some examples of other inputs.</p>
<h3 id="heading-the-textarea-input-field">The TextArea Input Field</h3>
<p>In React, the <code>textarea</code> is defined as a self-closing element just like the <code>input</code> element.</p>
<p>As expected, we will have the state manage the user’s input (i.e textarea message). So, update the state to include a <code>message</code> property like so:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [state, setState] = useState({
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">""</span>
});
</code></pre>
<p>Next, add a <code>textarea</code> element in the <code>form</code> like so:</p>
<pre><code class="lang-javascript">...
return (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            ...
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    Message
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"message"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{state.message}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
)
</code></pre>
<p>Take note of the <code>value</code> and <code>name</code> prop in the <code>textarea</code> element. Just like the input field, the string assigned to the <code>name</code> prop must be the same as what we declared in the state object.</p>
<h3 id="heading-the-select-input-field">The Select Input Field</h3>
<p>This is not different from the other input fields. As usual, we can make it a controlled input by first having the state manage the input data. Then add a <code>value</code> prop to the element and finally update it through the <code>onChange</code> handler function (but in our case, we don’t have to do anything here because we have the logic set already).</p>
<p>And don’t forget to add a <code>name</code> prop (to the element) that matches the name in the state. So let’s create a dropdown list with options to select car brands.</p>
<p>As expected, add a new property in the state. In my case, I will call it <code>carBrand</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [state, setState] = useState({
  ...
  carBrand: <span class="hljs-string">""</span>,
});
</code></pre>
<p>Then, add the <code>select</code> element just before the closing <code>&lt;/form&gt;</code> tag:</p>
<pre><code class="lang-javascript">...
return (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            ...
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    Favorite Car Brand
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"carBrand"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{state.carBrand}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"mercedes"</span>&gt;</span>Mercedes<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"bmw"</span>&gt;</span>BMW<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"audi"</span>&gt;</span>Audi<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
)
</code></pre>
<h3 id="heading-the-checkbox-input-field">The Checkbox Input Field</h3>
<p>Unlike the other input fields, the checkbox uses a <code>checked</code> prop (which is a Boolean attribute) instead of the <code>value</code> prop. The idea is that a checkbox is either checked or not.</p>
<p>We will need to adjust the handler function to accommodate the checkbox type of input. Ok, let’s start by adding a new property to the state. We can call it <code>isChecked</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [state, setState] = useState({
  ...
  isChecked: <span class="hljs-literal">false</span>,
});
</code></pre>
<p>Here, we assign a Boolean value of <code>false</code> so that the input field is unchecked by default. Next, add input checkbox just before the closing <code>&lt;/form&gt;</code> tag.</p>
<pre><code class="lang-javascript">...
return (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            ...
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                        <span class="hljs-attr">name</span>=<span class="hljs-string">"isChecked"</span>
                        <span class="hljs-attr">checked</span>=<span class="hljs-string">{state.isChecked}</span>
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                    /&gt;</span>
                    Remember Me?
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
)
</code></pre>
<p>Finally, update the <code>handleChange</code> function so you have:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleChange = <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
   <span class="hljs-keyword">const</span> value = e.target.type === <span class="hljs-string">"checkbox"</span> ? e.target.checked : e.target.value; 
    setState({
        ...state,
        [e.target.name]: value
    })
}
</code></pre>
<p>In this function, we cannot use the earlier logic to manage the checkbox because it doesn’t have the <code>value</code> but <code>checked</code> attribute. So you’d need to adjust it if you want the same <code>handleChange</code> to manage the checkbox.</p>
<p>As seen in the handler, we now target the <code>type</code> and the <code>checked</code> attribute from this event parameter, <code>e</code>. From there, we are using the ternary operator, which is an inline if-statement to check the input types and then assign their corresponding value (either Boolean <a target="_blank" href="http://e.target"><code>e.target</code></a><code>.checked</code> for the checkbox or <a target="_blank" href="http://e.target"><code>e.target</code></a><code>.value</code> for every other input types).</p>
<h3 id="heading-the-radio-input-field">The Radio Input Field</h3>
<p>The radio input types combine the input text and the checkbox type. In other words, they use both the <code>value</code> and the <code>checked</code> prop.</p>
<p>We will create radio inputs that allow users to select gender. As expected, let’s add that to the state.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [state, setState] = useState({
  ...
  gender: <span class="hljs-string">""</span>,
});
</code></pre>
<p>Then, add the <code>radio</code> inputs just before the closing <code>&lt;/form&gt;</code> tag:</p>
<pre><code class="lang-javascript">...
return (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            ...
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                        <span class="hljs-attr">name</span>=<span class="hljs-string">"gender"</span>
                        <span class="hljs-attr">value</span>=<span class="hljs-string">"male"</span>
                        <span class="hljs-attr">checked</span>=<span class="hljs-string">{state.gender</span> === <span class="hljs-string">"male"</span>}
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                    /&gt;</span>
                    Male
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-label"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">"form-input"</span>
                        <span class="hljs-attr">name</span>=<span class="hljs-string">"gender"</span>
                        <span class="hljs-attr">value</span>=<span class="hljs-string">"female"</span>
                        <span class="hljs-attr">checked</span>=<span class="hljs-string">{state.gender</span> === <span class="hljs-string">"female"</span>}
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                    /&gt;</span>
                    Female
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-button"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
)
</code></pre>
<p>What’s happening?</p>
<p>As you know already, once you have the state manage your input, you immediately assign the state property to the <code>name</code> prop of the input. You should know from HTML that radio group share the same name. This allows us to select only one button at a time.</p>
<p>Notice that the <code>value</code> prop in these inputs are static unlike that of text inputs where its value comes from the state.</p>
<p>And finally, with the <code>checked</code> prop, we are saying that if the condition assigned is <code>true</code>, that radio button should be checked.</p>
<p>Simple as that!</p>
<p>While working with inputs in a React application, these are the most popular and all that we cover in this article.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>We should handle input changes by writing controlled components. To do this, we attach an event handler function to the <code>onChange</code> event.</p>
<p>To handle form submission, we attach an <code>onSubmit</code> event handler to the form, and then get the <code>event</code> an object from the parameter and call <code>event.preventDefault</code> inside so we can run JavaScript code in the handler.</p>
<p>To handle multiple input changes with one <code>onChange</code> handler, we get the <code>name</code> and <code>value</code> properties from <code>event.target</code> from the handler’s parameter and update it with the dynamic property name feature available since ES6.</p>
<p><mark>Source Code</mark> =&gt; <a target="_blank" href="https://github.com/marville001/form-handling-react">https://github.com/marville001/form-handling-react</a></p>
<p>Be on the lookout for part 2 of this blog covering form validation using libraries such as <a target="_blank" href="https://react-hook-form.com/">react-hook-form</a> and <a target="_blank" href="https://formik.org/">formik</a>.</p>
<p>That's all for this article.</p>
<p>Thank you :)</p>
]]></content:encoded></item><item><title><![CDATA[How to Dockerize a NodeJs Application]]></title><description><![CDATA[We all know that getting an application up and running on a different machine is no simple task. You have to run through a lot of setup work, right from setting up the environment variables needed and the dependencies required to the runtime. This is...]]></description><link>https://blog.mmwangi.com/how-to-dockerize-a-nodejs-application</link><guid isPermaLink="true">https://blog.mmwangi.com/how-to-dockerize-a-nodejs-application</guid><category><![CDATA[Docker]]></category><category><![CDATA[Dockerfile]]></category><category><![CDATA[docker images]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Thu, 24 Nov 2022 20:00:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1667595570272/MGkef4k0z.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We all know that getting an application up and running on a different machine is no simple task. You have to run through a lot of setup work, right from setting up the environment variables needed and the dependencies required to the runtime. This is even not hard until we get to the point of automating the whole process of deployment. </p>
<p>This is a major problem in software development and a couple of technologies have come up trying to solve this challenge of differing environments, deployment configurations, and automation. <strong>Docker</strong> is the mostly used and effective solution.</p>
<p>To learn about the basics of docker, check out my intro blog to docker <a target="_blank" href="https://blog.thereactivedeveloper.com/docker-getting-started-for-beginners">Here</a>.</p>
<h3 id="heading-what-is-dockerization">What is Dockerization?</h3>
<p>This is the process of packaging your application, together with all its dependencies and environments into a container (a completely isolated running process).</p>
<p>Dockerizing an application involves identifying and specifying everything that your applications need to run into a Dockerfile and then building a Docker image using it. A Docker image is an environment that can be replicated and is guaranteed to run on other machines.</p>
<p>Dockerizing an application simply involves 3 steps</p>
<ul>
<li>Preparing a <code>Dockerfile</code>.</li>
<li>Building a Docker <code>image</code>.</li>
<li>Running a docker <code>container</code> from the image.</li>
</ul>
<p>So let's dive into dockerizing a Node.js app</p>
<h3 id="heading-setting-up-a-demo-nodejs-app">Setting Up a Demo Node.js App</h3>
<p>To make the demo for the concepts in this article, we will use a <a target="_blank" href="https://github.com/marville001">demo nodejs app</a> that provides an endpoint for fetching posts. The app uses the <a target="_blank" href="https://jsonplaceholder.typicode.com/">JSONPlaceholder</a> fake API. You can clone the app into your computer using the following command</p>
<pre><code>git clone https:<span class="hljs-comment">//github.com/marville001/docker-nodejs-demo</span>
</code></pre><p>Once you have downloaded the app, <code>cd</code> into the project folder and run <code>npm install</code> to install all the required dependencies. The app has one file index.js which should look as shown below.</p>
<pre><code><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> fetch = <span class="hljs-built_in">require</span>(<span class="hljs-string">"node-fetch"</span>);

<span class="hljs-keyword">const</span> app = express();

app.use(express.json());

app.get(<span class="hljs-string">"/posts"</span>, <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> URL = <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts?_limit=5"</span>;

        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(URL);
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

        res.status(<span class="hljs-number">200</span>).send(data)
    } <span class="hljs-keyword">catch</span> (error) {
        res.status(<span class="hljs-number">500</span>).json({
            <span class="hljs-attr">message</span>: <span class="hljs-string">"Failed To Get Posts"</span>,
            <span class="hljs-attr">error</span>: error.message,
        });
    }
});

<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">9000</span>;
app.listen(PORT, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`App running on post <span class="hljs-subst">${PORT}</span>`</span>));
</code></pre><p>Run the command <code>npm start</code> to start the application and in your browser go to <code>http://localhost:9000/posts</code> to view a list of 5 posts.</p>
<h3 id="heading-creating-a-dockerfile">Creating a Dockerfile</h3>
<p>There are many ways to use Docker, but the best way is through the creation of Dockerfiles. A Dockerfile essentially gives build instructions to Docker when you build a container image.</p>
<p>To get started, we need to specify which base image to pull from. We will specify the base image to be the official Node image since it gives us what we need to run our application and has a small footprint. To be specific we will use <code>node:16-alpine</code></p>
<p>Create a file called Dockerfile:</p>
<pre><code># Dockerfile

FROM node:<span class="hljs-number">16</span>-alpine

WORKDIR /app

COPY package*.json .

RUN npm install

# Copy the source files into the image
COPY .   .

EXPOSE <span class="hljs-number">9000</span>

CMD [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]
</code></pre><p>The Dockerfile consists of the following commands:</p>
<ul>
<li><strong>FROM</strong>: tells Docker what base image to use as a starting point. We specifies the base image to be the official <a target="_blank" href="https://hub.docker.com/_/node">Node.js Alpine Linux</a> image. Alpine Linux is used here due to its small size, which helps a lot when transporting images from one machine to the other</li>
<li><strong>WORKDIR</strong>: changes the active directory. For our case, it sets the working directory to <code>/app</code>. This directory will be created if it doesn't exist.</li>
<li><strong>RUN</strong>: executes commands inside the container.</li>
<li><strong>EXPOSE</strong>: tells Docker which ports should be mapped outside the container. We need to expose the port <code>9000</code> that the application will run on through this instruction:</li>
<li><strong>CMD</strong>: defines the command to run when the container starts.</li>
</ul>
<p>Building images should be fast, efficient, and reliable. Every command you execute results in a new layer that contains the changes compared to the previous layer.  These layers will stack on top of each other, adding functionality incrementally.</p>
<p>Create a file called <code>.dockerignore</code>:</p>
<pre><code>.git
.gitignore
node_modules/
</code></pre><p>The .dockerignore is similar to a .gitignore file and lets us safely ignore files or directories that shouldn’t be included in the final Docker build.</p>
<h3 id="heading-build-the-docker-image">Build the Docker Image</h3>
<p>Now that the Dockerfile is complete, it's time to build the Docker image according to the instructions in the file. This is achieved through the docker build command. You need to pass in the directory where the Dockerfile exists and your preferred name for the image:</p>
<pre><code>$ docker build -t demo-app .
</code></pre><p>You can run <code>docker images</code> to view some basic info about the created image:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669309834822/djMhSfhyR.png" alt="Doceker Images.png" /></p>
<h3 id="heading-run-the-docker-image-in-a-container">Run the Docker Image in a Container</h3>
<p>Use the docker run command to run your newly minted Docker image inside of a <a target="_blank" href="https://www.docker.com/resources/what-container">container</a>. Since the application has been built into the image, it has everything it needs to work.  It can be launched directly in an isolated process. Before you can access your running image inside the container, you must expose its port to the outside world through the --publish or -p flag. This lets you bind the port in the container to a port outside the container.</p>
<pre><code>docker run -p <span class="hljs-number">9000</span>:<span class="hljs-number">9000</span> demo-app
</code></pre><p>The command above starts the demo-app image inside of a container and exposes port 9000 inside the container to port 9000 outside the container. You can access the posts through <code>http://localhost:9000/posts</code>.</p>
<p>That's all from this article. Keep coding :)</p>
<p>Thank you</p>
]]></content:encoded></item><item><title><![CDATA[Docker Getting Started for Beginners]]></title><description><![CDATA[While the demand for new applications is rising, the pressure to keep up with this demand rises too. As a developer, it becomes easier when you have the right tools. Docker is one of such tool, especially for anyone who is into the DevOps path. It's ...]]></description><link>https://blog.mmwangi.com/docker-getting-started-for-beginners</link><guid isPermaLink="true">https://blog.mmwangi.com/docker-getting-started-for-beginners</guid><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Martin Mwangi]]></dc:creator><pubDate>Sun, 30 Oct 2022 13:00:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1666944462325/4ftM7ZQYu.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While the demand for new applications is rising, the pressure to keep up with this demand rises too. As a developer, it becomes easier when you have the right tools. Docker is one of such tool, especially for anyone who is into the DevOps path. It's a platform dedicated to the development, shipment, and running of any application. </p>
<p>In this article, we will take a look at the best way to get started with using Docker. You will learn how to create and deploy Docker apps. Then you can also update and share your containerized app.</p>
<p>What we will cover</p>
<ul>
<li>What is docker</li>
<li>The problem Docker solves</li>
<li>Docker Terminologies</li>
<li>Docker installation</li>
<li>Docker commands and how to use them</li>
</ul>
<h2 id="heading-what-is-docker">What Is Docker</h2>
<p>In much-simplified terms, Docker is a platform that simplifies the process of building, running, managing, and distributing applications. It is designed to deliver your applications way faster as compared to when not using it. Its key claim is that you can swiftly provide software by separating your software applications from your regular infrastructure. And all of this is accomplished by simply virtualizing the operating system that is installed and functioning on your machine.</p>
<h2 id="heading-the-problem-docker-solves">The Problem Docker Solves</h2>
<h3 id="heading-the-problem">The Problem</h3>
<p>We can consider a scenario where we have 3 different Python applications each using a different version of Python as well as its associated libraries and dependencies. We want to deploy and host these applications on a single server. The problem becomes that we can't have different versions of Python installed on the same machine which prevents us from running the applications on the same computer.</p>
<h3 id="heading-solution-without-docker">Solution without docker</h3>
<p>The solution would be hosting them on three different machines which is not the case we want or getting a machine powerful enough to host and run three virtual machines on it. These two solutions are very costly and have more work for procuring and maintaining the hardware. You also have to consider that you have to set up the Operating System on each machine and the Python environment required for each app manually which is quite cumbersome and repetitive. Now, let's look at docker, how it works and how it can help us solve this problem in a much simpler way.</p>
<p>To work with docker you just require one machine / operating system with Docker installed in it (Docker host). Instead of having to install a virtual machine for each application we have, we just package the application with its dependencies in one unit called a container. Let's look at some docker terminologies before diving even deeper</p>
<h2 id="heading-docker-terminologies">Docker Terminologies</h2>
<ol>
<li><strong>Docker Host</strong> - The machine on which docker is installed and running.</li>
<li><strong>Docker Engine</strong> - a containerization technology based on open-source for containerizing and building your applications. This is responsible for the overall functioning of the Docker platform.</li>
<li><strong>Docker Image</strong> - This is a template that contains the application, and all the dependencies required to run that application on Docker.</li>
<li><strong>Docker Container</strong> - This is the running instance of the Docker Image</li>
<li><strong>Dockerfile</strong> - Is a simple document that contains instructions on how to create Docker Images</li>
<li><strong>Docker Compose</strong> - This a tool for outlining and running multi-container Docker applications. (We will cover this in another article)</li>
<li><strong>Docker Hub</strong> - This is the official online repository where you can store, distribute custom images or find other Docker Images available for public use</li>
</ol>
<h2 id="heading-docker-installation">Docker Installation</h2>
<p>Before using docker locally or on a machine instance running on the cloud, you need to have Docker installed. Below are links to install docker on Ubuntu, Debian, and Windows. The steps are straightforward.</p>
<ul>
<li><a target="_blank" href="https://docs.docker.com/docker-for-windows/install/">Windows Installation</a></li>
<li><a target="_blank" href="https://docs.docker.com/install/linux/docker-ce/debian/">Debian Linux Installation</a></li>
<li><a target="_blank" href="https://docs.docker.com/install/linux/docker-ce/ubuntu/">Ubuntu Installation</a></li>
</ul>
<p>If you just want to practice using docker commands, You can use the <a target="_blank" href="https://labs.play-with-docker.com/">Docker Playground</a></p>
<h2 id="heading-docker-commands">Docker Commands</h2>
<p>Now that we have already installed docker (assuming you have followed the steps in the links above to install it), let's check some docker commands.</p>
<p><strong>docker create</strong></p>
<p>Allows you to create new containers. It has the following syntax</p>
<pre><code>docker create [options] IMAGE [commands] [<span class="hljs-built_in">arguments</span>]
</code></pre><p>NB: The things enclosed in brackets are optional. You can also run <code>docker create --help</code> to learn more about each.</p>
<p>Example: <code>docker create ubuntu -t -i ubuntu bash</code></p>
<p>This will create a container using the ubuntu image. The -t and -i options tell Docker to give the container a terminal so that the user can communicate with it.  If the container is launched, the create command is also used to run the bash command.
Docker will first check if you have the image locally and if not it will go ahead and download it from the Docker hub and use it to create the container.</p>
<p><strong>docker ps</strong></p>
<p>Allows you to view the currently running containers. To view all containers including those already exited, add -a to the command. <code>docker ps -a</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667126983594/3FLSK19gT.png" alt="Docker ps -a.png" /></p>
<p>Let's explain some of the details returned by the command</p>
<ul>
<li><em>CONTAINER ID</em>  - A singular string consisting of alphanumeric characters, related to each container.</li>
<li><em>IMAGE</em>  - Name of the Docker image used to create this container.</li>
<li><em>COMMAND</em>  - Any application-specific command(s) that must be executed when the container is started.</li>
<li><em>CREATED</em>  - It displays the time taken since this container has been created.</li>
<li><em>STATUS</em>  - This shows the present status of the container.</li>
<li><em>PORTS</em>  - This shows whether port mappings are defined for the container or not.</li>
<li><em>NAMES</em>  - Each container is also given a unique name in addition to the CONTAINER ID. 
If you want to give the container a name, use the --name (double hyphen name) option in the docker create or docker run command.</li>
</ul>
<p><strong>docker images</strong></p>
<p>To view all the Docker images on your computer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667127119781/oF-qVOmQk.png" alt="docker images.png" /></p>
<p>Let's explain some of the details returned by the command</p>
<ul>
<li><em>REPOSITORY</em>  - This represents the unique name of the Docker Image.</li>
<li><em>TAG</em>  - Each image is associated with a unique tag. A tag basically represents a version of the image.</li>
<li><em>IMAGE ID</em>  - A unique string consisting of alpha-numeric characters, associated with each image.</li>
<li><em>CREATED</em>  - This shows the time elapsed since this image has been created.</li>
<li><em>SIZE</em>  - This shows the size of the image.</li>
</ul>
<p>Once you have an image locally on your computer, you can create a container based on it using the docker run command. Eg <code>docker run hello-world</code>. To explicitly name the container when running it, use the –name option, like this: <code>docker run --name helloworld hello-world</code></p>
<p><strong>docker rmi</strong></p>
<p>This command allows us to remove an image from the Docker host.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667129987244/STML00GHu.png" alt="docker rmi.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667127444453/0ah8mRwcl.png" alt="docker run.png" /></p>
<p><strong>docker rm</strong></p>
<p>Once you are done with a container and no longer need it, you can delete it using the <em>docker rm</em> command. You need to first get the container id using the <code>docker ps -a</code> command and specify the id together with the <em>docker rm</em> command.</p>
<p><code>docker rm 1d0284a0eae1</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667127881283/81cKC1_Dc.png" alt="docker rm .png" /></p>
<p><strong>docker start</strong> and <strong>docker stop</strong></p>
<p>If you just want to stop a container from running without deleting it, you can use the <code>docker stop id</code> command to halt a container.
Then to start the halted container just use <code>docker start id</code>.</p>
<p><strong>docker restart</strong></p>
<p>This command restarts any running container.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=eGz9DS-aIeY">https://www.youtube.com/watch?v=eGz9DS-aIeY</a></div>
<p>That's all from this article. I will prepare another article on how to create custom images using a Dockerfile. Until then, keep coding :)</p>
<p>Thank you.</p>
]]></content:encoded></item></channel></rss>