<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vedansh Mehra</title>
    <description>The latest articles on DEV Community by Vedansh Mehra (@imvedanshmehra).</description>
    <link>https://dev.to/imvedanshmehra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F401640%2Fda9b2632-7565-47ff-bb7f-fa01d5847973.png</url>
      <title>DEV Community: Vedansh Mehra</title>
      <link>https://dev.to/imvedanshmehra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imvedanshmehra"/>
    <language>en</language>
    <item>
      <title>Virtual Scrolling in React: Implementation from scratch and using react-window</title>
      <dc:creator>Vedansh Mehra</dc:creator>
      <pubDate>Sun, 05 Nov 2023 19:53:49 +0000</pubDate>
      <link>https://dev.to/imvedanshmehra/virtual-scrolling-in-react-implementation-from-scratch-and-using-react-window-336o</link>
      <guid>https://dev.to/imvedanshmehra/virtual-scrolling-in-react-implementation-from-scratch-and-using-react-window-336o</guid>
      <description>&lt;p&gt;How many times you've been in a situation where you have to render a list of items in your web application? It is a very common thing when building modern web apps these days. Well, the problem comes when you have to render very huge datasets let's say 100,000 or more data all at once, and that too without any pagination. This will pollute the DOM and occupy so much of the browser's memory leading to a lot of performance issues and degraded user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Virtual scrolling&lt;/strong&gt; is one of the techniques that can save your back in this situation by only rendering the items that the user actually wants to see while the rest of the items will be loaded virtually as the user scrolls towards them instead of rendering everything at once.&lt;/p&gt;

&lt;p&gt;In this article, we'll see what virtual scrolling is and how can we implement virtual scroll in a React application to render a list of 100,000 items with no pagination.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Virtual Scrolling? 🧐
&lt;/h2&gt;

&lt;p&gt;As we have already discussed, rendering a huge list of data on the DOM with no pagination can make the application slower by polluting the DOM, consuming too much of the browser's memory, and on top of that the end user is not going to consume all the data at once, they'll only see a subset of that data and then scroll through the list to see more data.&lt;/p&gt;

&lt;p&gt;Virtual scroll or &lt;strong&gt;Windowing&lt;/strong&gt; is a technique in web app development that will only render items that are visible in the viewport while the rest of the items will be virtualized by top and bottom padding. As we scroll through the list, the older items will be destroyed and new items will be displayed based on the position of the scrollbar. This way we won't put too much load on the DOM by rendering everything at once. Using this technique in the correct scenario can greatly improve the performance of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do we need Virtualization? 💭
&lt;/h2&gt;

&lt;p&gt;Now that we know what virtual scrolling is, the question comes - &lt;strong&gt;"Do we always need virtual scroll?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer to this question should be quite obvious, If you are building a web app where you have to render a huge list of items without any pagination and you truly care about the performance then definitely virtual scrolling is what you can use.&lt;/p&gt;

&lt;p&gt;While it is a good way to improve performance there are a few scenarios in which you might not need to implement virtual scrolling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If you are rendering a list of less than 50 or 100 data&lt;/strong&gt;- If you are rendering a list with a very items say 50 or 100 items, virtual scrolling might just be an overhead and would not make any huge difference on the performance of the app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When rendering a paginated list&lt;/strong&gt;- When rendering a list with some sort of &lt;a href="https://en.wikipedia.org/wiki/Pagination" rel="noopener noreferrer"&gt;pagination&lt;/a&gt;, then obviously virtual scrolling might not be of any use because the whole point of virtual scrolling is to render list items efficiently when there is no pagination implemented.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Virtualization in React app from scratch
&lt;/h2&gt;

&lt;p&gt;Now when we have some idea about virtual scrolling and when to use it, we'll see how can we implement virtual scrolling in a react application without using any third-party tools.&lt;/p&gt;

&lt;p&gt;To get started with this approach, we'll make a few assumptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the height of each row in the list will be fixed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;total number of items to be rendered in the list is known upfront.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we meet the above condition, let's create a new React app and build a &lt;code&gt;VirtualScroll&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

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

const VirtualScroll = ({
  rowHeight,
  totalItems,
  items,
  visibleItemsLength,
  containerHeight,
}) =&amp;gt; {
  // Calculate the total height of the container
  const totalHeight = rowHeight * totalItems;
  //   Current scroll position of the container
  const [scrollTop, setScrollTop] = useState(0);
  // Get the first element to be displayed
  const startNodeElem = Math.ceil(scrollTop / rowHeight);
  // Get the items to be displayed
  const visibleItems = items?.slice(
    startNodeElem,
    startNodeElem + visibleItemsLength
  );
  //  Add padding to the empty space
  const offsetY = startNodeElem * rowHeight;

  const handleScroll = (e) =&amp;gt; {
    // set scrollTop to the current scroll position of the container.
    setScrollTop(e?.currentTarget?.scrollTop);
  };

  return (
    &amp;lt;div
      style={{
        height: containerHeight,
        overflow: "auto",
        border: "5px solid black",
      }}
      onScroll={handleScroll}
    &amp;gt;
      &amp;lt;div style={{ height: totalHeight }}&amp;gt;
        &amp;lt;div style={{ transform: `translateY(${offsetY}px)` }}&amp;gt;
          {visibleItems}
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;In the code above, we are doing very basic maths, we first calculate the total height of the container &lt;code&gt;totalHeight&lt;/code&gt; by multiplying a single row's height &lt;code&gt;rowHeight&lt;/code&gt; with total items to be rendered &lt;code&gt;totalItems&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10v45q1j152ny0ax3tjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10v45q1j152ny0ax3tjt.png" alt="Virtual Scroll row height and container height" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we divide the container's scroll position from the top &lt;code&gt;scrollTop&lt;/code&gt; with a single row's height &lt;code&gt;rowHeight&lt;/code&gt; to get the starting node element &lt;code&gt;startNodeElem&lt;/code&gt; which will be rendered on the list, we are also using &lt;code&gt;Math.ceil&lt;/code&gt; to round up the value.&lt;/p&gt;

&lt;p&gt;Then we slice &lt;code&gt;totalItems&lt;/code&gt; to only show items starting from the &lt;code&gt;startNodeElem&lt;/code&gt; till &lt;code&gt;startNodeElem + visibleItemsLength&lt;/code&gt;. So, let's say our &lt;code&gt;startNodeElem = 5&lt;/code&gt;, then we'll show items from the 5th position till &lt;code&gt;5 + visibleItemsLength&lt;/code&gt; considering &lt;code&gt;visibleItemsLength&lt;/code&gt; to be &lt;strong&gt;20&lt;/strong&gt; in this case. So our component will render items starting from the 5th position till &lt;code&gt;5 + 20 = 25&lt;/code&gt; position.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpngptmea4pjpzl5ip9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpngptmea4pjpzl5ip9h.png" alt="Virtual scroll top and bottom padding and visible content" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now every time the user scrolls the container, the value of &lt;code&gt;scrollTop&lt;/code&gt; will be re-calculated and &lt;code&gt;startNodeElem&lt;/code&gt; will be updated based on the scroll position and we'll shift the nodes down using &lt;code&gt;transform: translateY&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;We can now use our &lt;code&gt;VirtualScroll&lt;/code&gt; component to render a list of items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import VirtualScroll from "./virtual-scroll";
// Total items to be rendered
const totalItems = 100000;

const items = new Array(totalItems).fill(null).map((_, index) =&amp;gt; {
  return (
    // Height of the div should be the same as what we are sending in rowHeight
    &amp;lt;div style={{ height: "70px" }} key={index}&amp;gt;
      &amp;lt;p&amp;gt;Row Number - {index}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
});

function App() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;Virtual Scroll From Scratch&amp;lt;/h1&amp;gt;
      &amp;lt;VirtualScroll
        rowHeight={70}
        totalItems={totalItems}
        containerHeight="500px"
        items={items}
        visibleItemsLength={20}
      /&amp;gt;
    &amp;lt;/&amp;gt;
  );
}
export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are rendering a list of 100000 items and we have set &lt;code&gt;containerHeight&lt;/code&gt; to 500px and the height of each row or the &lt;code&gt;rowHeight&lt;/code&gt; to 70px.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F350w9c15ek1mpcy760iu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F350w9c15ek1mpcy760iu.gif" alt="Virtual scroll implementation gif" width="1096" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now start your application to see virtual scrolling in action.&lt;/p&gt;

&lt;p&gt;As you can see, when we are scrolling through the list we are not piling up extra nodes but instead, the previous nodes are destroyed and we are rendering new nodes based on the container's scroll position.&lt;/p&gt;

&lt;p&gt;Here's the sandbox output with the above implementation:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/virtualisation-in-react-pvg2cx"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You might be noticing some white space while scrolling and that is because every time the container is scrolled the entire DOM is manipulated and we are re-calculating everything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So this was a very naive implementation of virtual scrolling from scratch in a react application that can of course be more optimized for better results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Scrolling in React using react-window
&lt;/h2&gt;

&lt;p&gt;As we have seen in the previous section we can implement virtual scrolling from scratch. In this section, we'll discuss a third-party tool called &lt;a href="https://github.com/bvaughn/react-window" rel="noopener noreferrer"&gt;react-window&lt;/a&gt; that allows us to implement virtual scrolling in a much easier way.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;react-window&lt;/code&gt; is a very lightweight React package that lets you render a virtualized list while removing all the extra work that you might have to put in when implementing a solution from scratch.&lt;/p&gt;

&lt;p&gt;To get started with react-window, we first need to install it into our react application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Yarn
yarn add react-window

# NPM
npm install --save react-window
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With react-window, we can basically render lists with fixed row height and also the lists with dynamic row height, we'll go off by each of them one at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  react-window with fixed size list
&lt;/h3&gt;

&lt;p&gt;If you have to render list items with fixed row height you can use the &lt;code&gt;FixedSizeList&lt;/code&gt; component from react-window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FixedSizeList } from "react-window";

const Row = ({ index, style }) =&amp;gt; (
  /* Adding style attribute is very important here
    it supplies the row height to the elements. */
  &amp;lt;div style={style}&amp;gt;Row {index}&amp;lt;/div&amp;gt;
);

// Create a component with Fixed Size example
const ReactWindowFixedSizeEx = () =&amp;gt; (
  &amp;lt;FixedSizeList height={150} itemCount={100000} itemSize={35} width={300}&amp;gt;
    {Row}
  &amp;lt;/FixedSizeList&amp;gt;
);

export { ReactWindowFixedSizeEx };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we have set the container's height to &lt;strong&gt;150px&lt;/strong&gt; and each of the row's height will be &lt;strong&gt;35px&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-window-fixed-size-list-example-m5tkt9"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  react-window with variable size list
&lt;/h3&gt;

&lt;p&gt;If you have to render list items with dynamic row height, you can use the &lt;code&gt;VariableSizeList&lt;/code&gt; component from react-window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { VariableSizeList } from "react-window";
import "./App.css";
const totalItemsCount = 100000;

// Set random row heights
const rowHeights = new Array(totalItemsCount)
  .fill(true)
  .map(() =&amp;gt; 12 + Math.round(Math.random() * 50));

const getItemSize = (index) =&amp;gt; rowHeights[index];

const Row = ({ index, style }) =&amp;gt; (
  &amp;lt;div style={style} className={index % 2 ? "odd" : "even"}&amp;gt;
    Row {index}
  &amp;lt;/div&amp;gt;
);

// Create a component with Fixed Size example
const ReactWindowVariableSizeEx = () =&amp;gt; (
  &amp;lt;VariableSizeList
    height={500}
    itemCount={totalItemsCount}
    itemSize={getItemSize} 
    width={300}
  &amp;gt;
    {Row}
  &amp;lt;/VariableSizeList&amp;gt;
);

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

&lt;/div&gt;



&lt;p&gt;In the above example, the container's height will be &lt;strong&gt;500px&lt;/strong&gt; while the row's height will be arbitrary and we are making use of the &lt;code&gt;itemSize&lt;/code&gt; prop to provide the height of a particular row.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the above code, we are setting arbitrary row height for each of the rows but in real application there should be some actual logic to calculate the heights of the rows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-window-variable-size-list-example-64ynfm"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Awesome! So we now have seen different ways to implement virtual scrolling in a react application, here is the GitHub repo link with each of these implementations if you want to check - &lt;a href="https://github.com/imvedanshmehra/virtual-scroll-react" rel="noopener noreferrer"&gt;https://github.com/imvedanshmehra/virtual-scroll-react&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Words 🗣️
&lt;/h2&gt;

&lt;p&gt;Virtualization is a very good technique to improve the performance of the application when rendering a large set of data without pagination, you can either implement it from scratch or use packages like &lt;code&gt;react-window&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can take a step further and make it more optimized by lazy loading the data to be rendered by using &lt;code&gt;infinite scroll&lt;/code&gt; which is yet another very good technique to render a large set of data.&lt;/p&gt;

&lt;p&gt;With this, I hope you enjoyed reading this article as much as I enjoyed writing it and I am hoping that you could get to learn something from it.&lt;/p&gt;

&lt;p&gt;If you like the blog, please show your love by clicking on the ❤️ icon below and leave your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;If you'd like to read more such articles you can give me a follow. Also connect with me on &lt;a href="https://twitter.com/imvedanshmehra" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/imvedanshmehra/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; where I regularly share content related to web development, Javascript, &amp;amp; software engineering best practices.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>performance</category>
    </item>
    <item>
      <title>Deploy Node-Express-MySQL app on Railway for free (no credit card required)</title>
      <dc:creator>Vedansh Mehra</dc:creator>
      <pubDate>Mon, 03 Jul 2023 19:33:26 +0000</pubDate>
      <link>https://dev.to/imvedanshmehra/deploy-node-express-mysql-app-on-railway-for-free-no-credit-card-required-121p</link>
      <guid>https://dev.to/imvedanshmehra/deploy-node-express-mysql-app-on-railway-for-free-no-credit-card-required-121p</guid>
      <description>&lt;p&gt;Heroku was one of the go-to hosting providers for most of our backend projects, but since they have phased out their free tier in 2022 most of the people are looking for alternate ways to deploy their backend project. While there are a lot of free hosting providers available out there, I recently came across &lt;a href="https://railway.app/" rel="noopener noreferrer"&gt;Railway&lt;/a&gt; when I had to deploy one of my Node-Express-MySQL-based app. One thing, I liked about Railway (and I am sure most of you will like it too) is that you don't even need to save your credit/debit card details when you are starting with their free tier. Of course, you will have to use some payment methods when your app grows and your trial period ends but for most of us, we don't want to save our cards for our hobby projects that we are not very serious about.&lt;/p&gt;

&lt;p&gt;With that said, in this article, we will be talking about how can we deploy a Node-Express-MySQL based application on Railway for free without a credit card.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most of the deployment steps should remain the same irrespective of which tech stack you choose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Project Overview
&lt;/h3&gt;

&lt;p&gt;Before we get down to the setup, let's understand what exactly we are going to build. We will create a very basic Node-based API for our shopping list, where the API will return an id for the item, item name, and item quantity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is not about creating APIs using NodeJS and therefore I will not go very deep into it but I'll still try to explain most of the steps for you to follow along.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To get along you must have &lt;code&gt;git&lt;/code&gt; installed and a &lt;code&gt;GitHub&lt;/code&gt; account setup as Railway uses your Github account for continuous deployment.&lt;/p&gt;

&lt;p&gt;If you want to follow along with the development, I am assuming that you already have &lt;code&gt;node-js&lt;/code&gt; installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a basic Node server
&lt;/h3&gt;

&lt;p&gt;The first step towards our project is to create a very minimalist node server that we can run on our local machine.&lt;/p&gt;

&lt;p&gt;Let's start by creating a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir node-mysql-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move inside of the project now to initialize a basic &lt;code&gt;package.json&lt;/code&gt; file and install a few dependencies and dev-dependencies required to create our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y


npm install express mysql2 cors


npm install -D nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For any Node application to run, we generally need an entry point file which is the root file that gets served to the server, in our case the entry point file will be named as &lt;code&gt;app.js&lt;/code&gt; (a very common entry point file name for most of the node apps).&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;package.json&lt;/code&gt; file and create a &lt;code&gt;start&lt;/code&gt; script, this script will be used to start our development server and serve our entry point file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// node-mysql-app/package.json

{
  "name": "mysql-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    // Create a start script
    "start": "nodemon app.js",
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "mysql2": "^3.4.3"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have everything set up to create our basic node server, let's create a new file called &lt;code&gt;app.js&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// node-mysql-app/app.js

const express = require("express");

const app = express();

app.get("/", (req, res) =&amp;gt; {
  res.send("Hello world");
});

// Server will listen to port 8080
app.listen(8080, 
    () =&amp;gt; console.log(`Server is listening on port ${8080}`)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm start&lt;/code&gt; to start the dev server.&lt;/p&gt;

&lt;p&gt;We now have a very basic node server that returns &lt;code&gt;"Hello world"&lt;/code&gt; when you navigate to &lt;code&gt;localhost:8080&lt;/code&gt; .&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting MySQL DB on Railway
&lt;/h3&gt;

&lt;p&gt;If everything went well and you can see the desired response on your localhost then navigate to &lt;a href="https://railway.app/" rel="noopener noreferrer"&gt;https://railway.app/&lt;/a&gt; to create a new Railway account (log in if you already have one).&lt;/p&gt;

&lt;p&gt;Once you have logged in to your Railway account, you should see a dashboard like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F854xqe93of03ss7xtq4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F854xqe93of03ss7xtq4l.png" alt="" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;"New Project"&lt;/strong&gt; option to create a new project and choose "MySQL" from the given options.&lt;/p&gt;

&lt;p&gt;In a couple of seconds, a new instance of a MySQL database should be hosted on your dashboard.&lt;/p&gt;

&lt;p&gt;Open your newly created instance of MySQL database and you should see a panel like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7ezyzr110dumo8g206a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7ezyzr110dumo8g206a.png" alt="Railway.app MySQL Panel" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, as you can see we have two options to create a new table inside our database. You can either use their GUI to create a new table by clicking on the &lt;strong&gt;"Create table"&lt;/strong&gt; button or you can run your own SQL query to create a table. I'll go with running the custom query but feel free to use GUI if you want to.&lt;/p&gt;

&lt;p&gt;So, to create a new table I'll run the following SQL query under the &lt;strong&gt;"Query"&lt;/strong&gt; tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE shopping_list (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    quantity VARCHAR(255),
    PRIMARY KEY (id)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new table named &lt;code&gt;shopping_list&lt;/code&gt; which will have an &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;quantity&lt;/code&gt; columns in it.&lt;/p&gt;

&lt;p&gt;Let's now add some mock data to our newly created table so that we can test that everything is working fine when we will complete our project. To add some data to the table we will run the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO shopping_list (name, quantity)
VALUES
    ('Bananas', '3'),
    ('Milk', '1 liter'),
    ('Eggs', '1 dozen');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have added some dummy data to our table, we are now ready to connect our Node app with our MySQL database which is hosted on Railway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting Node app to MySQL database
&lt;/h3&gt;

&lt;p&gt;To connect our Node app with the MySQL database, go back to your code editor and create a new file - &lt;code&gt;db.js&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// node-mysql-app/db.js

const mysql = require("mysql2");

connection = mysql.createConnection({
  host: // &amp;lt;MYSQL host&amp;gt;,
  port: // &amp;lt;MYSQL port&amp;gt;,
  user: // &amp;lt;MYSQL username&amp;gt;,
  password: // &amp;lt;MYSQL password&amp;gt;,
  database: // &amp;lt;MYSQL database name&amp;gt;,
});
connection.connect((err) =&amp;gt; {
  if (err) {
    console.error("CONNECT FAILED", err.code);
  } else console.log("CONNECTED");
});

module.exports = { connection };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Replace the comments with your actual MySQL config variables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the above code, you need to replace the commented values with your MySQL config variables that you can find under the &lt;strong&gt;"Connection"&lt;/strong&gt; tab on the Railway app inside your MySQL DB instance. For me, the config looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dhawltlyrsg5mkcrwb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dhawltlyrsg5mkcrwb9.png" alt="Railway.app MySQL connection tab" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this is enough to connect to the MySQL database there is one problem with the current setup though.&lt;/p&gt;

&lt;p&gt;Exposing secret values like DB username and password is not a good practice. To avoid this we generally create an &lt;code&gt;.env&lt;/code&gt; file and store the variables there and then read the values from the &lt;code&gt;.env&lt;/code&gt; file instead of hard-coding them.&lt;/p&gt;

&lt;p&gt;So, let's create a &lt;code&gt;.env&lt;/code&gt; file at the root of our app with the following environment variables in it and replace the commented code with your actual DB config values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MYSQL_HOST=// &amp;lt;MYSQL host&amp;gt;
MYSQL_PORT=// &amp;lt;MYSQL port&amp;gt;
MYSQL_USER=// &amp;lt;MYSQL user&amp;gt;
MYSQL_PASSWORD=// &amp;lt;MYSQL password&amp;gt;
MYSQL_DB=// &amp;lt;MYSQL DB name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to read the environment variables from our Javascript we need to install a package &lt;code&gt;dotenv&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, go back to the &lt;code&gt;db.js&lt;/code&gt; file and do the following changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mysql = require("mysql2");
// Config dotnev
require("dotenv").config();

// Replace the hard-coded values with the env variables
connection = mysql.createConnection({
  host: process.env.MYSQL_HOST,
  port: process.env.MYSQL_PORT,
  user: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DB,
});
connection.connect((err) =&amp;gt; {
  if (err) {
    console.error("CONNECT FAILED", err.code);
  } else console.log("CONNECTED");
});

module.exports = { connection };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should be able to successfully connect to our MySQL database. Let's go to the &lt;code&gt;app.js&lt;/code&gt; file and create a &lt;code&gt;GET&lt;/code&gt; request which will take all the items from the &lt;code&gt;shopping_list&lt;/code&gt; table and return a JSON with those values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// node-mysql-app/app.js

const express = require("express");
const { connection } = require("./db");

const app = express();

app.get("/api/shopping-list", (req, res) =&amp;gt; {
  connection.query("SELECT * FROM shopping_list", (err, data) =&amp;gt; {
    if (err) return callback(err, null);
    res.status(200).json({
      status: "success",
      length: data.length,
      data,
    });
  });
});

app.listen(8080, () =&amp;gt; console.log(`Server is listening on port ${8080}`));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, start the server again using &lt;code&gt;npm start&lt;/code&gt; and navigate to &lt;code&gt;localhost:8080/api/shopping-list&lt;/code&gt; and you should see a JSON returned with the items from the &lt;code&gt;shopping_list&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;Hooray! 🎉&lt;br&gt;&lt;br&gt;
Now as our app is working perfectly fine locally, it's time to deploy our Node server on Railway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying Node server on Railway
&lt;/h3&gt;

&lt;p&gt;To deploy the application on Railway, we first need to push the code to GitHub. I am assuming that you already know how to push the code to GitHub so I am not going to cover that in this article but make sure that you add &lt;code&gt;.env&lt;/code&gt; file and &lt;code&gt;node_modules&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; so that you don't accidentally push these two files on GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about the &lt;code&gt;.gitignore&lt;/code&gt; file here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have pushed the code on GitHub, let's go back to the Railway dashboard and create a new project and this time choose &lt;strong&gt;"Deploy from Github repo"&lt;/strong&gt; from the given options.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You will have to connect your GitHub account to the Railway app for continuous deployment of the project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Choose the project that you want to deploy from all the projects in your GitHub account and then click on &lt;strong&gt;Deploy Now&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawpnln8ras1vl59agco2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawpnln8ras1vl59agco2.png" alt="Railway.app deploy from Github dashboard" width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! Your app is all set for the deployment and now all you need to do is add the environment variables that are needed to run the application.&lt;/p&gt;

&lt;p&gt;Go to the &lt;strong&gt;"Variables"&lt;/strong&gt; tab to add the environment variables where you will get two options. You can either add the variables 1 at a time or you can add multiple variables at once using the Raw editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvvrs6i0bgrc5goildyf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvvrs6i0bgrc5goildyf.png" alt="Railway.app variables tab" width="800" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to replace the commented values with your actual MySQL config variable values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are done with all the steps needed to deploy the application on Railway. Finally, we will have to either generate a random domain name which is provided by Railway, or select a custom domain if you already have one.&lt;/p&gt;

&lt;p&gt;Go to the &lt;strong&gt;Settings&lt;/strong&gt; tab and under Domains you should see the two options, I don't want to use a custom domain so I'll go with &lt;strong&gt;Generate Domain&lt;/strong&gt; to generate a random domain name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkhee6nenduhcfxc54aq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkhee6nenduhcfxc54aq.png" alt="Railway.app settings tab" width="800" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are all done. 😮💨&lt;/p&gt;

&lt;p&gt;Now navigate to your &lt;code&gt;&amp;lt;domain-name/api/shopping-list&amp;gt;&lt;/code&gt; and you should see your application live running on the Railway server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Notes
&lt;/h3&gt;

&lt;p&gt;Though Railway was a very good fit for my requirement and it might fit with your requirements as well yet I am quite new to it and I might not be very well aware of its trade-offs or how compatible it is for large-scale applications. I will keep this blog updated in case I find anything about it.&lt;/p&gt;

&lt;p&gt;Also if you liked this article please show some love to it and follow me on &lt;a href="https://twitter.com/imvedanshmehra" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; where I share more content about software engineering and web development.&lt;/p&gt;

&lt;p&gt;Thank you for reading along, see you in the next article. 👋&lt;/p&gt;

</description>
      <category>node</category>
      <category>mysql</category>
      <category>express</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Monorepo setup with Npm Workspaces &amp; Lerna</title>
      <dc:creator>Vedansh Mehra</dc:creator>
      <pubDate>Sun, 30 Apr 2023 09:59:25 +0000</pubDate>
      <link>https://dev.to/imvedanshmehra/monorepo-setup-with-npm-workspaces-lerna-2adm</link>
      <guid>https://dev.to/imvedanshmehra/monorepo-setup-with-npm-workspaces-lerna-2adm</guid>
      <description>&lt;p&gt;Monorepos lets you manage multiple repositories into one single repository but managing and publishing them can be very tedious as the repositories grow.&lt;br&gt;&lt;br&gt;
Lerna is a powerful tool that can be used to manage and publish monorepos in Javascript/Typescript projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lerna is a fast, modern build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we will see how we can set up a monorepo with Lerna and Npm workspaces.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are interested in setting up a monorepo with&lt;/em&gt; &lt;strong&gt;&lt;em&gt;Vite, Pnpm, and Typescript&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;you can check out my previous blog&lt;/em&gt; &lt;a href="https://dev.to/imvedanshmehra/setting-up-a-monorepo-with-vite-typescript-and-pnpm-workspaces-19ak-temp-slug-6616308"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Why use Lerna?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;To use monorepos well, you need a good monorepo tool, and Lerna is exactly that. Lerna is fast, widely used, and battle tested.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Monorepos can have tens if not hundreds of packages, and managing all of them together can become very difficult. Lerna can rescue us in this situation by doing the heavy lifting of managing the tasks in different packages, versioning, code deployment, etc.&lt;/p&gt;

&lt;p&gt;Lerna has some great in-built features which make managing monorepos surprisingly easier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Running tasks within multiple packages&lt;/strong&gt; : Lerna gives us an out-of-the-box solution to run tasks inside multiple packages together using &lt;code&gt;lerna run&lt;/code&gt; command. For example, Let's say you have 3 packages inside your monorepo and you want to run the &lt;code&gt;test&lt;/code&gt; script for all of them, with Lerna all you have to do is just run &lt;code&gt;npx lerna run test&lt;/code&gt; command from the root of your project and it will run the &lt;code&gt;test&lt;/code&gt; script inside each of your packages (You must have defined the &lt;code&gt;test&lt;/code&gt; script in package.json for all the projects respectively in order to make this work properly).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Visualize the workspace&lt;/strong&gt; : When the workspace becomes very huge it is common for a new developer to face difficulty in understanding the hierarchy of the workspace and understand how different packages are linked together. Lerna uses &lt;code&gt;Nx&lt;/code&gt; to help visualize the workspace graph. Simply run &lt;code&gt;npx nx graph&lt;/code&gt; and it will launch a project visualization graph on your browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check the complete list of Lerna features &lt;a href="https://lerna.js.org/docs/introduction#why-lerna" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Who uses Lerna?
&lt;/h2&gt;

&lt;p&gt;Lerna is being used by many different teams including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Jest&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create React App&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nx&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NestJS&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To follow along, you must have &lt;code&gt;Node&lt;/code&gt; installed in your system which I am assuming that you would already have. Other than that, some basic knowledge of Javascript/Typescript and React will help in understanding the code that we are going to write.&lt;/p&gt;
&lt;h3&gt;
  
  
  Project Overview
&lt;/h3&gt;

&lt;p&gt;For the sake of this article, our monorepo will have two packages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;common&lt;/strong&gt; : A shared library that can be used by multiple packages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;client&lt;/strong&gt; : A basic React app that will consume the &lt;code&gt;common&lt;/code&gt; package and will render the components on UI.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Let's start off by creating a new directory at your desired location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir npm-lerna-monorepo

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

&lt;/div&gt;



&lt;p&gt;Then, move inside your newly created directory and initialize a Lerna workspace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# npm-lerna-monorepo
npx lerna init

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

&lt;/div&gt;



&lt;p&gt;This command will do the following things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file if it is not already present and add &lt;code&gt;lerna&lt;/code&gt; as a dev dependency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create and configure a new &lt;code&gt;lerna.json&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure npm workspaces inside &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;packages&lt;/code&gt; directory that will contain all our monorepo packages.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; lerna.json
 .gitignore
 package.json
 packages

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

&lt;/div&gt;



&lt;p&gt;Now, in order to use Typescript in our project, we need to install a few dependencies at the root level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i typescript @types/node -D

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

&lt;/div&gt;



&lt;p&gt;Once the above dependencies are installed, create a common &lt;code&gt;tsconfig.json&lt;/code&gt; file that will be extended by all the other packages of our app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": false,
    "noImplicitAny": false,
    "removeComments": true,
    "noLib": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es6",
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "moduleResolution": "node",
    "lib": ["es6"]
  },
  "exclude": ["node_modules"]
}

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

&lt;/div&gt;



&lt;p&gt;Now we can start creating our packages, to do that let's go inside the &lt;code&gt;packages&lt;/code&gt; directory and create the &lt;code&gt;common&lt;/code&gt; package first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest common --template react-ts

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

&lt;/div&gt;



&lt;p&gt;We should now have a &lt;code&gt;common&lt;/code&gt; package inside our &lt;code&gt;packages&lt;/code&gt; directory, now let's move inside the &lt;code&gt;common&lt;/code&gt; directory and run &lt;code&gt;npm install&lt;/code&gt; to install all the required dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# npm-lerna-monorepo/packages/common
npm install

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

&lt;/div&gt;



&lt;p&gt;In order to use the base Typescript configuration that we've defined at the root level, we need to add the following snippet at the beginning of our &lt;code&gt;tsconfig.json&lt;/code&gt; inside the common package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/common/tsconfig.json
{
  "extends": "../../tsconfig.json",
  ...
}

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

&lt;/div&gt;



&lt;p&gt;We will now go ahead and create a Button component and will export it so that it can be used by the other packages in our monorepo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/common/src/components/Button.tsx

interface ButtonProps {
    buttonText: string;
}

const Button = ({ buttonText }: ButtonProps) =&amp;gt; {
    return (
        &amp;lt;button&amp;gt;{buttonText}&amp;lt;/button&amp;gt;
    )
}

export default Button;

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

&lt;/div&gt;



&lt;p&gt;Now export this Button component from &lt;code&gt;main.tsx&lt;/code&gt; file which will be our entry point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/common/src/main.tsx
import Button from "./components/Button"

export { Button }

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

&lt;/div&gt;



&lt;p&gt;We will set &lt;code&gt;main.tsx&lt;/code&gt; as our entry point by setting the &lt;code&gt;main&lt;/code&gt; property in &lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Also, as per the common workspace naming convention of monorepos we'll change the name of the &lt;code&gt;common&lt;/code&gt; package to &lt;code&gt;@npm-lerna-monorepo/common&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/common/package.json
{
  "name": "@npm-lerna-monorepo/common", // Change the package name
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "main": "./src/main.tsx", // Define the entrypoint file
  ...
}

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

&lt;/div&gt;



&lt;p&gt;We should now be able to import components from the &lt;code&gt;common&lt;/code&gt; package very easily after linking it with the &lt;code&gt;client&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Let's now create our &lt;code&gt;client&lt;/code&gt; package, for that we'll move inside the packages directory and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# npm-lerna-monorepo/packages
npm create vite@latest client --template react-ts

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

&lt;/div&gt;



&lt;p&gt;Our project structure after running the above command should look somewhat like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3sq783xf70hoecxkjli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3sq783xf70hoecxkjli.png" alt="project-structure" width="364" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's update the &lt;code&gt;tsconfig.json&lt;/code&gt; of the client package now to extend the base Typescript configuration that we've defined at the root level.&lt;/p&gt;

&lt;p&gt;To do that add the following line of code at the beginning of &lt;code&gt;client/tsconfig.json&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/client/tsconfig.json
{
  "extends": "../../tsconfig.json",
  ...
}

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

&lt;/div&gt;



&lt;p&gt;Now add the &lt;code&gt;common&lt;/code&gt; package as one of the dependencies for the &lt;code&gt;client&lt;/code&gt; package, we can add the common package using the name that we've defined in its &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/client/package.json
{
  "name": "@npm-lerna-monorepo/client", // Updated the name
  ...
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "@npm-lerna-monorepo/common": "*" // Added common package
    ...
  },

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

&lt;/div&gt;



&lt;p&gt;We've also changed the name of the &lt;code&gt;client&lt;/code&gt; package according to the monorepos workspace naming convention.&lt;/p&gt;

&lt;p&gt;Let's link both of our packages together by running &lt;code&gt;npm install&lt;/code&gt; from the root level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# npm-lerna-monorepo
npm install

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

&lt;/div&gt;



&lt;p&gt;This will link both packages together and now we can easily import the Button component from the &lt;code&gt;common&lt;/code&gt; package and use it in our &lt;code&gt;client&lt;/code&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// npm-lerna-monorepo/packages/client/src/App.tsx
import { Button } from "@npm-lerna-monorepo/common"

const App = () =&amp;gt; {
  return &amp;lt;Button buttonText="Hello world" /&amp;gt;
}

export default App;

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

&lt;/div&gt;



&lt;p&gt;Run the dev server for &lt;code&gt;client&lt;/code&gt; package now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# npm-lerna-monorepo/packages/client
npm run dev

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

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;localhost:5173&lt;/code&gt; on your favorite web browser and you should see a button rendered on the UI.&lt;/p&gt;

&lt;p&gt;So we have successfully setup up our monorepo using Npm workspaces and Lerna and while you are in our local environment, any changes you will make to the &lt;code&gt;common&lt;/code&gt; package will immediately reflect on the &lt;code&gt;client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hooray 🎉&lt;/p&gt;

&lt;p&gt;You can find the complete code of the setup &lt;a href="https://github.com/imvedanshmehra/npm-lerna-monorepo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;In this article, we have seen how we can set up and manage a monorepo with Lerna and Npm workspaces.&lt;/p&gt;

&lt;p&gt;Though Lerna is a great tool, you don't need to include it in all of your monorepos it's mainly suitable for large applications where you have multiple packages that you need to manage simultaneously.&lt;/p&gt;

&lt;p&gt;While this article was majorly focused on the setup part, if you are interested in reading more about how we can use Lerna to build and publish our monorepos please let me know in the comments.&lt;/p&gt;

&lt;p&gt;I hope this blog could a little value to you. If you liked it please share it with those who might find it helpful and show some to the article.&lt;/p&gt;

&lt;p&gt;You can also follow me on &lt;a href="https://twitter.com/imvedanshmehra" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; where I post more content on Javascript, React, Software Engineering, and other stuff.&lt;/p&gt;

</description>
      <category>monorepo</category>
      <category>npm</category>
      <category>lerna</category>
      <category>react</category>
    </item>
    <item>
      <title>Package React Applications using Docker</title>
      <dc:creator>Vedansh Mehra</dc:creator>
      <pubDate>Sat, 25 Mar 2023 10:09:16 +0000</pubDate>
      <link>https://dev.to/imvedanshmehra/package-react-applications-using-docker-47dk</link>
      <guid>https://dev.to/imvedanshmehra/package-react-applications-using-docker-47dk</guid>
      <description>&lt;p&gt;As React developers, we all have gone through the pain of deploying our apps on different environments or setting them up on different machines which indeed is no fun at all. Docker helps us containerize our React applications with all the packages and dependencies which are needed to run the app on different servers with ease. In this article, we will talk about the step-by-step process to containerize React applications using Docker for easier and quick deployments.&lt;/p&gt;

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

&lt;p&gt;This blog post is not a complete Docker guide so I will not dive very deep into this topic. But just to get some gist, Docker is a containerization tool that packages your application along with all of its dependencies into containers which help in faster shipping, testing, and deployment.&lt;/p&gt;

&lt;p&gt;When you create a docker image it shares a part of your machine's kernel and gives you an independent and isolated environment to run your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of using Docker with your React app
&lt;/h2&gt;

&lt;p&gt;Using Docker with React applications can be useful in many ways, a few of them are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent environment:&lt;/strong&gt; Docker helps in creating a consistent environment to run your application irrespective of the operating system that you are using on your host machine. This can help in avoiding many underlying issues which might occur due to the inconsistency between the environments where you are running your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bundling of dependencies together:&lt;/strong&gt; Docker helps in bundling all the dependencies which are required to run the application together to avoid the chance of conflicts or versioning related issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster deployments:&lt;/strong&gt; Docker can significantly simplify the deployment process but building the app into a container that can easily be deployed to different environments. Additionally, Docker has a very powerful caching mechanism which makes the deployment process even faster.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up Docker for React application
&lt;/h2&gt;

&lt;p&gt;Now that you are convinced that Docker can be a useful tool when working with React applications, let's see how we can set it up together with a React application.&lt;/p&gt;

&lt;p&gt;To get started, we need a React application. We can use an existing application or create a new one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Dockerfile
&lt;/h3&gt;

&lt;p&gt;Once we have a React application set up, the next step is to create an &lt;code&gt;Dockerfile&lt;/code&gt; at the root of the project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🗒 Note&lt;/strong&gt; : The file name should be &lt;code&gt;Dockerfile&lt;/code&gt; (with no extensions).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt; is a text document that has all the instructions required to build an image.&lt;/p&gt;

&lt;p&gt;Every Dockerfile should start with &lt;code&gt;FROM&lt;/code&gt; instruction, which specifies a base image that can be used to build the subsequent image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

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

&lt;/div&gt;



&lt;p&gt;In our case, we are using &lt;code&gt;node:alpine&lt;/code&gt; as our base image which is a significantly lighter version of node and makes the download and deployment a lot faster.&lt;/p&gt;

&lt;p&gt;Let's now copy all the files from our React application to our Docker image using the &lt;code&gt;COPY&lt;/code&gt; instruction.&lt;/p&gt;

&lt;p&gt;COPY instruction copies all the files and directories from the source path to the destination path inside our image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

COPY . .

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

&lt;/div&gt;



&lt;p&gt;Using the above instruction we copied all the files from the root of our app to our image.&lt;/p&gt;

&lt;p&gt;Now that we have all the files and directories copied, we can now run &lt;code&gt;npm install&lt;/code&gt; inside our image to install all the required dependencies for our application. To do so, we can use &lt;code&gt;RUN&lt;/code&gt; instruction which is used to run commands inside the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

COPY . .

RUN npm install

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

&lt;/div&gt;



&lt;p&gt;This will now install all the required dependencies inside our container and we should now have everything we need to start our React application.&lt;/p&gt;

&lt;p&gt;We can start our application using the &lt;code&gt;CMD&lt;/code&gt; instruction which is used to assign default executables to the container which will be executed when we run the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

COPY . .

RUN npm install

CMD ["npm", "start"]

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

&lt;/div&gt;



&lt;p&gt;We are using &lt;code&gt;["npm", "start"]&lt;/code&gt; as our default command which is used to spin up our React server.&lt;/p&gt;

&lt;p&gt;It's time now to build our image, we can run &lt;code&gt;docker build .&lt;/code&gt; command from our terminal to build the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build .

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

&lt;/div&gt;



&lt;p&gt;Once the image is built successfully it returns an image ID that can be used to run the image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmiwwytq1a6i1yhfgm53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmiwwytq1a6i1yhfgm53.png" alt="Output of docker build command" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tagging an image in Docker
&lt;/h2&gt;

&lt;p&gt;Using the image ID to run the image might not be the most convenient thing to do, to avoid that docker has a way to tag our images to a specific name and then run the images using that name instead of using the image ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t react-docker .

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

&lt;/div&gt;



&lt;p&gt;We can use &lt;code&gt;-t&lt;/code&gt; flag with the docker build command to tag an image to a specific name, in our case I am using " &lt;strong&gt;react-docker&lt;/strong&gt;" for our image name, but we can use any other name that we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running images in Docker
&lt;/h2&gt;

&lt;p&gt;Once the image is successfully tagged to a specific name, we can run the image using &lt;code&gt;docker run&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run react-docker

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

&lt;/div&gt;



&lt;p&gt;This command will execute the default command that we have given to &lt;code&gt;CMD&lt;/code&gt; instruction in our Dockerfile. In our case, that command was &lt;code&gt;npm start&lt;/code&gt; which will start the React server.&lt;/p&gt;

&lt;p&gt;Once the image starts running, we should see similar to the following message in our terminal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l67eoehecttdmu0doug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l67eoehecttdmu0doug.png" alt="Console message once the app is running on docker" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tells us that our app is running successfully on &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Port mapping in Docker
&lt;/h2&gt;

&lt;p&gt;After running the &lt;code&gt;docker run&lt;/code&gt; command shown above, if you will try to visit &lt;code&gt;localhost:3000&lt;/code&gt; you will notice a very weird thing. You will see that nothing is showing up on localhost even though the above message says that our app is up and running🤔.&lt;/p&gt;

&lt;p&gt;This is because when we executed the default command it started the server inside our container and we are trying to access that server on our host machine but there is no actual connection between these two different environments.&lt;/p&gt;

&lt;p&gt;To solve this issue Docker has a technique called " &lt;strong&gt;port mapping&lt;/strong&gt;", also known as " &lt;strong&gt;port forwarding&lt;/strong&gt;" which is used to export the Docker containers port on our host machine and allow accessing services running inside our containers from our host machine itself.&lt;/p&gt;

&lt;p&gt;The easiest way to map ports in Docker is by using &lt;code&gt;-p&lt;/code&gt; flag along with the docker run command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 3000:3000 react-docker

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

&lt;/div&gt;



&lt;p&gt;This will expose all the services running on port 3000 on our container to our host machine.&lt;/p&gt;

&lt;p&gt;If we will try to visit &lt;code&gt;localhost:3000&lt;/code&gt; on our browser now, we should have our app running successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing a few gotchas with the current setup
&lt;/h2&gt;

&lt;p&gt;So far, so good! Our app is running properly and everything else seems to be working fine but let me tell you, there are a few gotchas in the current configuration that needs our attention.&lt;/p&gt;

&lt;p&gt;The first thing is we are copying every file and directory from our React application to the root of our container, which is generally not a good practice.&lt;/p&gt;

&lt;p&gt;It is recommended to organize all our files inside a working directory in the container for better maintainability and to avoid conflicts with the default files. To do that, we can use &lt;code&gt;WORKDIR&lt;/code&gt; instruction to create a working directory inside our container and all the subsequent instructions will run inside the working directory only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

WORKDIR /app

COPY . .

RUN npm install

CMD ["npm", "start"]

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

&lt;/div&gt;



&lt;p&gt;This will now create a working directory called &lt;code&gt;app&lt;/code&gt; inside the container and all the instructions after that will run inside the same working directory.&lt;/p&gt;

&lt;p&gt;The other big gotcha with the current setup is whenever we make any changes to any of the files and rebuild our image, all the instructions are re-running including the &lt;code&gt;npm install&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;This is fine as far as we have a small application with only a few dependencies but as the project grows and we add multiple dependencies running &lt;code&gt;npm install&lt;/code&gt; after every change can be very time-consuming and is not something that we want.&lt;/p&gt;

&lt;p&gt;Docker has a very useful cache mechanism, which caches each layer of the image when we run the image and during the next build it checks the cache to see if it has the cached version and re-uses it instead of rebuilding the image.&lt;/p&gt;

&lt;p&gt;To take advantage of this cached mechanism it's important to structure our Docker configuration in such a way that the frequently changing instructions are placed at the end of the file.&lt;/p&gt;

&lt;p&gt;In our case, we want to run &lt;code&gt;npm install&lt;/code&gt; only when we have made any changes to the &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine

WORKDIR /app

COPY ./package.json /app/package.json
RUN npm install

COPY . .
RUN npm install

CMD ["npm", "start"]

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

&lt;/div&gt;



&lt;p&gt;This will now only run &lt;code&gt;npm install&lt;/code&gt; only when there is some change to the &lt;code&gt;package.json&lt;/code&gt; file otherwise it will use the cached version and only re-run the instructions which have changed.&lt;/p&gt;

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

&lt;p&gt;In this article, we have learned how to containerize React applications using Docker and some of the recommended configurations to speed up the build process.&lt;/p&gt;

&lt;p&gt;Overall, we can use Docker with our React application to ensure consistent build across different environments which will result in faster deployment and testing of our application.&lt;/p&gt;

&lt;p&gt;That's it for this article, I hope you liked it. Please feel free to add your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;If you liked this article, there is a huge possibility that you will like my tweets too. Please check out my &lt;a href="https://twitter.com/imvedanshmehra" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; account for more content about web development, Javascript, React, and a lot more.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Setting up a monorepo with Vite, Typescript, and pnpm workspaces</title>
      <dc:creator>Vedansh Mehra</dc:creator>
      <pubDate>Tue, 28 Feb 2023 12:48:30 +0000</pubDate>
      <link>https://dev.to/imvedanshmehra/setting-up-a-monorepo-with-vite-typescript-and-pnpm-workspaces-1ipk</link>
      <guid>https://dev.to/imvedanshmehra/setting-up-a-monorepo-with-vite-typescript-and-pnpm-workspaces-1ipk</guid>
      <description>&lt;p&gt;Monorepos are hot these days and it can significantly improve the development workflow and productivity among teams. In this article, we will talk about how to set up a monorepo with Vite, Typescript, and pnpm workspaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a monorepo?
&lt;/h2&gt;

&lt;p&gt;Before we jump into the setup, we first need to understand what is a monorepo and why should we care about it.&lt;/p&gt;

&lt;p&gt;Monorepo is a repository that contains many distinct projects which are somewhat dependent on each other but they are logically independent and different teams can work on them in isolation.&lt;/p&gt;

&lt;p&gt;Let's consider an example where we are building an application and we have two projects inside of it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Shared: This will have all our shared components that can be used by different projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Main: This is going to be our main project which will be the consumer of our &lt;code&gt;Shared&lt;/code&gt; package.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One way to work with this type of project is a multi-repo approach where we create two separate repositories and host them at the npm registry. Then the consumer app can install it from the npm registry and use it how we import and use &lt;code&gt;React&lt;/code&gt;, &lt;code&gt;Tailwind&lt;/code&gt;, &lt;code&gt;Material-UI&lt;/code&gt; and other packages.&lt;/p&gt;

&lt;p&gt;The problem with this type of workflow is every time we will make any new changes to the &lt;code&gt;shared&lt;/code&gt; package, we will have to publish the app again to the npm registry for the consumer app to get the latest changes and use them.&lt;/p&gt;

&lt;p&gt;Monorepos can significantly improve this workflow by packaging both of these projects into a single repository and importing components directly from the workspace instead of importing them from the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup with pnpm workspaces
&lt;/h2&gt;

&lt;p&gt;Now that we have an idea about what monorepos are and what problems they solve, let's dive right into the setup and see how we can set up a basic monorepo with &lt;code&gt;pnpm workspaces&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To follow along you must have &lt;code&gt;pnpm&lt;/code&gt; and &lt;code&gt;node&lt;/code&gt; installed in your machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Scaffold a new project
&lt;/h3&gt;

&lt;p&gt;The first thing that we need to do for our setup is, create a new project which we will call "pnpm-monorepo" you can of course name it whatever you want to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir pnpm-monorepo

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

&lt;/div&gt;



&lt;p&gt;Then let's go inside the root of our project and initialize a &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm monorepo
pnpm init

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

&lt;/div&gt;



&lt;p&gt;At this point, you should have a basic &lt;code&gt;package.json&lt;/code&gt; at the root of your project with somewhat similar code as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/package.json
{
  "name": "pnpm-monorepo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

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

&lt;/div&gt;



&lt;p&gt;Now, let's install some of our root-level dependencies that we are going to use across the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monorepo
pnpm add -D typescript typescript-node

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

&lt;/div&gt;



&lt;p&gt;Once the common dependencies are installed let's create our base Typescript configuration with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/tsconfig.base.json
{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "noUnusedLocals": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "jsx": "react-jsx",
    "moduleResolution": "node"
  }
}

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

&lt;/div&gt;



&lt;p&gt;This is the default Typescript configuration that I have written for my project you can customize it based on your project's requirements.&lt;/p&gt;

&lt;p&gt;Next, we will create our &lt;code&gt;tsconfig.json&lt;/code&gt; file which will extend our &lt;code&gt;tsconfig.base.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/tsconfig.json
{
  "extends": "./tsconfig.base.json"
}

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

&lt;/div&gt;



&lt;p&gt;That's all we need for our Typescript configuration.&lt;/p&gt;

&lt;p&gt;Now let's create a &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; file at the root of our project that will tell &lt;code&gt;pnpm&lt;/code&gt; what packages we will have inside our monorepo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;pnpm-workspace&lt;/code&gt; makes it surprisingly easier to add and manage multiple packages in a project.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monrepo/pnpm-workspace.yaml
packages:
  - "./packages/**"

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

&lt;/div&gt;



&lt;p&gt;We can add as many packages as we want to &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; by adding the relative path of the packages in this file, for our project we are adding our &lt;code&gt;packages&lt;/code&gt; directory and all of its child directories to the workspace.&lt;/p&gt;

&lt;p&gt;Now we will create both of our &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;shared&lt;/code&gt; packages that we discussed above inside the &lt;code&gt;packages&lt;/code&gt; directory. Our &lt;code&gt;main&lt;/code&gt; project will be a &lt;code&gt;Vite&lt;/code&gt; application and the &lt;code&gt;shared&lt;/code&gt; project will have some shared code that we will use inside our main app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Vite application
&lt;/h3&gt;

&lt;p&gt;Let's first create the packages directory at the root level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monorepo
mkdir packages

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

&lt;/div&gt;



&lt;p&gt;Now we will create our &lt;code&gt;main&lt;/code&gt; app inside of the packages directory which will be a &lt;code&gt;Vite&lt;/code&gt; application. To do that navigate inside &lt;code&gt;pnpm-monorepo/packages&lt;/code&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monorepo/packages
pnpm create vite

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

&lt;/div&gt;



&lt;p&gt;I am using React &amp;amp; Typescript but the following steps should work irrespective of which framework/library you select.&lt;/p&gt;

&lt;p&gt;Now let's create our second package in the packages directory, we will call it &lt;code&gt;shared.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monorepo/packages
mkdir shared

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

&lt;/div&gt;



&lt;p&gt;At this point, your project's structure should look somewhat similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwo28r3yipjoeqiegca63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwo28r3yipjoeqiegca63.png" alt="screenshot showing how the project structure should look at this point" width="504" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have our packages directory and inside it, we have our &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;shared&lt;/code&gt; packages.&lt;/p&gt;

&lt;p&gt;Let's now go inside our &lt;code&gt;main&lt;/code&gt; package and change the following in &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/packages/main/package.json
{
"name": "@pnpm-monorepo/main"
...
}

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

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;pnpm&lt;/code&gt; to properly identify that this package is part of our workspace, we need to change the name property of the package to &lt;code&gt;@root-name/package-name&lt;/code&gt; . In this case, our root name is &lt;code&gt;pnpm-monorepo&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Now let's go inside our &lt;code&gt;shared&lt;/code&gt; package and do the same but first, we need to create a &lt;code&gt;package.json&lt;/code&gt; file inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monorepo/packages/shared
pnpm init

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

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;package.json&lt;/code&gt; file inside our &lt;code&gt;shared&lt;/code&gt; package, now let's change the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/packages/second/package.json
{
    "name": "@pnpm-monorepo/shared"
}

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

&lt;/div&gt;



&lt;p&gt;That's it for the configuration part, now we should be able to import packages from the workspace similar to how we do for other npm packages.&lt;/p&gt;

&lt;p&gt;Let's create a &lt;code&gt;index.ts&lt;/code&gt; file inside our &lt;code&gt;shared&lt;/code&gt; package with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/packages/shared/index.ts
export const sayHi = (userName: string) =&amp;gt; console.log(`Hi ${userName}`)

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

&lt;/div&gt;



&lt;p&gt;We have a basic &lt;code&gt;sayHi&lt;/code&gt; function which takes a &lt;code&gt;userName&lt;/code&gt; as parameter and console log a message saying "Hi" to them.&lt;/p&gt;

&lt;p&gt;Now let's go inside our &lt;code&gt;main&lt;/code&gt; package and import our &lt;code&gt;shared&lt;/code&gt; package by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pnpm-monorepo/packages/main
pnpm add @pnpm-monorepo/shared

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

&lt;/div&gt;



&lt;p&gt;According to &lt;code&gt;pnpm&lt;/code&gt; docs, if we do &lt;code&gt;pnpm add&lt;/code&gt; within a workspace, it first tries to find that package within the workspace, and only if it is unable to find the package within the workspace it goes to the npm registry to install it.&lt;/p&gt;

&lt;p&gt;As we already have &lt;code&gt;@pnpm-monorepo/shared&lt;/code&gt; within our workspace, it will install it from the workspace itself.&lt;/p&gt;

&lt;p&gt;At this point your &lt;code&gt;package.json&lt;/code&gt; inside you &lt;code&gt;main&lt;/code&gt; app should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/packages/main/package.json
{
...
"dependencies": {
    "@pnpm-monorepo/shared": "workspace:^1.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
...
}

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

&lt;/div&gt;



&lt;p&gt;That's it, now we should be able to import variables/functions from our &lt;code&gt;shared&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Let's go inside our &lt;code&gt;main/App.tsx&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pnpm-monorepo/packages/main/App.tsx
import { sayHi } from "@pnpm-monorepo/shared";

const App = () =&amp;gt; {
  sayHi("Vedansh");
  return &amp;lt;h1&amp;gt;Main app&amp;lt;/h1&amp;gt;;
};
export default App;

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

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;pnpm install&lt;/code&gt; and &lt;code&gt;pnpm dev&lt;/code&gt; inside &lt;code&gt;main&lt;/code&gt; app, a new dev server should spin up and you should see the following output at your &lt;a href="http://localhost:5173/" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuogn6ktm74yiix9w7knj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuogn6ktm74yiix9w7knj.png" alt="screenshot of localhost" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So that's it, this was our very basic monorepo setup with pnpm-workspaces, Vite, and Typescript. Monorepos is a great solution for large-scale applications where you don't want to manage multiple repositories for multiple packages and instead you want to package all of them together into one repository.&lt;/p&gt;

&lt;p&gt;If you want the complete code of this project you can find it &lt;a href="https://github.com/imvedanshmehra/pnpm-monorepo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading, if you are still here consider following me for more blogs. You can also connect with me on &lt;a href="https://twitter.com/imvedanshmehra" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/vedanshmehra/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; where I keep sharing regular content related to web development and Javascript.&lt;/p&gt;

</description>
      <category>critique</category>
      <category>discuss</category>
      <category>sideprojects</category>
      <category>featurerequest</category>
    </item>
    <item>
      <title>Difference between useMemo and useCallback</title>
      <dc:creator>Vedansh Mehra</dc:creator>
      <pubDate>Sat, 25 Feb 2023 08:11:04 +0000</pubDate>
      <link>https://dev.to/imvedanshmehra/difference-between-usememo-and-usecallback-1h7b</link>
      <guid>https://dev.to/imvedanshmehra/difference-between-usememo-and-usecallback-1h7b</guid>
      <description>&lt;p&gt;Re-render is at the heart of React applications, Re-render happens when React components need to update the UI with new data. But there are times when some unnecessary re-renders can decrease the overall performance of the application. React has some in-built tools to prevent these unnecessary rerenders - &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;. Both of these hooks are used to reduce the re-render of a react app.&lt;/p&gt;

&lt;p&gt;In this article, we are going to talk about what is the actual difference between these two hooks and when to use one over another.&lt;/p&gt;

&lt;h2&gt;
  
  
  When does react component re-renders?
&lt;/h2&gt;

&lt;p&gt;In general, React components re-render due to one of the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When &lt;code&gt;state&lt;/code&gt; of the component changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the parent component re-renders.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the value of &lt;code&gt;context&lt;/code&gt; provider changes, all the components using the &lt;code&gt;context&lt;/code&gt; would re-render.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When is re-rendering a problem?
&lt;/h2&gt;

&lt;p&gt;Re-rendering itself is not a problem. React is so fast in performing these re-renders that most of the time it can handle them without users noticing anything. However, there are cases when these re-renders can slow down the application, especially when unnecessary re-render happens on heavy components that compute complex values.&lt;/p&gt;

&lt;h2&gt;
  
  
  An example showing unnecessary re-render of a component
&lt;/h2&gt;

&lt;p&gt;To illustrate this with an example, we will create a &lt;code&gt;Parent&lt;/code&gt; and a &lt;code&gt;Child&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Parent = () =&amp;gt; {
  const [num, setNum] = useState(0);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{num}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setNum(num + 1)}&amp;gt;+&amp;lt;/button&amp;gt;
      &amp;lt;Child /&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

const Child = () =&amp;gt; {
  console.log("Child component re-rendered...");

  return (
    &amp;lt;h1&amp;gt;I am Child Component&amp;lt;/h1&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;p&gt;We created a &lt;code&gt;Parent&lt;/code&gt; component which has a button element and a state &lt;code&gt;num&lt;/code&gt; and every time we click on the button element the state updates and as a result, we see the updated value of &lt;code&gt;num&lt;/code&gt; on the UI.&lt;/p&gt;

&lt;p&gt;However, you might notice that every time we click on the button element the &lt;code&gt;Child&lt;/code&gt; component also re-renders, we know that because every time we click on the button we see &lt;strong&gt;Child component re-rendered...&lt;/strong&gt; printed on the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcjvvaq708zntq9vd9es.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcjvvaq708zntq9vd9es.gif" alt="Browser window showing an example of unnecessary re-render" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to prevent unnecessary re-render using useMemo?
&lt;/h2&gt;

&lt;p&gt;React has a built-in hook that can help us solve this problem - &lt;code&gt;useMemo&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;useMemo(() =&amp;gt; function, [])&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; takes a function and dependency array and it returns a memoized value.&lt;/p&gt;

&lt;p&gt;In the above example, we have seen how &lt;code&gt;Child&lt;/code&gt; component is re-rendering unnecessarily whenever we click on the button element in the &lt;code&gt;Parent&lt;/code&gt; component. Let's see how we can prevent this re-render using &lt;code&gt;useMemo&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Parent = () =&amp;gt; {
  const [num, setNum] = useState(0);
  const getChild = useMemo(() =&amp;gt; &amp;lt;Child /&amp;gt;, []) // Wrap the Child component inside useMemo hook.

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{num}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setNum(num + 1)}&amp;gt;+&amp;lt;/button&amp;gt;
      {getChild}
    &amp;lt;/&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;p&gt;This should now prevent &lt;code&gt;Child&lt;/code&gt; component from re-rendering whenever the state updates in the &lt;code&gt;Parent&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr39iragnnt02rwhwj2u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr39iragnnt02rwhwj2u.gif" alt="Browser window showing how useMemo has prevent unnecessary re-render" width="3580" height="1620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A tricky catch with useMemo
&lt;/h2&gt;

&lt;p&gt;We have seen how &lt;code&gt;useMemo&lt;/code&gt; can solve the problem of unnecessary re-render but there is a catch. Let's find it out with the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Parent = () =&amp;gt; {
  const [num, setNum] = useState(0);

  const clickHandler = () =&amp;gt; {
    // Do something...
  }

  const getChild = useMemo(() =&amp;gt; &amp;lt;Child handleClick={clickHandler}/&amp;gt;, [clickHandler])

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{num}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setNum(num + 1)}&amp;gt;+&amp;lt;/button&amp;gt;
      {getChild}
    &amp;lt;/&amp;gt;
  )
}

const Child = ({handleClick}) =&amp;gt; {
  console.log("Child component re-rendered...");

  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;I am Child Component&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;Button inside child&amp;lt;/button&amp;gt; 
    &amp;lt;/&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;p&gt;We added a button inside the &lt;code&gt;Child&lt;/code&gt; component which will call a callback function whenever it is clicked. It will get that callback function from its props.&lt;/p&gt;

&lt;p&gt;Then, we create a &lt;code&gt;clickHandler&lt;/code&gt; function inside the &lt;code&gt;Parent&lt;/code&gt; component and passed that function as a dependency to &lt;code&gt;useMemo&lt;/code&gt; and then we passed that function as a prop to the &lt;code&gt;Child&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;This will again cause the same problem that we faced earlier. Every time the state changes in the &lt;code&gt;Parent&lt;/code&gt; component our Child component will re-render.&lt;/p&gt;

&lt;p&gt;This is happening because whenever a component re-renders in react, the functions inside that component are also created again. So in this case, whenever the &lt;code&gt;Parent&lt;/code&gt; component is re-rendering due to a change in its state the &lt;code&gt;clickHandler&lt;/code&gt; function is created again which rerenders the &lt;code&gt;Child&lt;/code&gt; component.&lt;/p&gt;

&lt;h2&gt;
  
  
  useCallback to Rescue
&lt;/h2&gt;

&lt;p&gt;React has another built-in hook that can help us solve this problem - &lt;code&gt;useCallback&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;useCallback(() =&amp;gt; function, [])&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;useCallback&lt;/code&gt; is very similar to &lt;code&gt;useMemo&lt;/code&gt;, the main difference is that the &lt;code&gt;useMemo&lt;/code&gt; returns a memoized value whereas &lt;code&gt;useCallback&lt;/code&gt; returns a memoized function.&lt;/p&gt;

&lt;p&gt;Let's see how we can solve this problem using &lt;code&gt;useCallback&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Parent = () =&amp;gt; {
  const [num, setNum] = useState(0);

  // Wrap the clickHandler function with useCallback
  const clickHandler = useCallback(() =&amp;gt; {
    // Do something...
  }, []);

  const getChild = useMemo(() =&amp;gt; &amp;lt;Child handleClick={clickHandler} /&amp;gt;, [
    clickHandler
  ]);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{num}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setNum(num + 1)}&amp;gt;+&amp;lt;/button&amp;gt;
      {getChild}
    &amp;lt;/&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;We just need to wrap the &lt;code&gt;clickHandler&lt;/code&gt; function with &lt;code&gt;useCallback&lt;/code&gt; hook to solve this problem. Thereafter, whenver the &lt;code&gt;Parent&lt;/code&gt; component re-renders &lt;code&gt;clickHandler&lt;/code&gt; will return the memoized function until one or more of its dependencies has not changed and due to this the &lt;code&gt;Child&lt;/code&gt; component will not re-render unnecessarily.&lt;/p&gt;

&lt;p&gt;Here is the complete code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Parent = () =&amp;gt; {
  const [num, setNum] = useState(0);

  const clickHandler = useCallback(() =&amp;gt; {
    // Do something...
  }, []);

  const getChild = useMemo(() =&amp;gt; &amp;lt;Child handleClick={clickHandler} /&amp;gt;, [
    clickHandler
  ]);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{num}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setNum(num + 1)}&amp;gt;+&amp;lt;/button&amp;gt;
      {getChild}
    &amp;lt;/&amp;gt;
  );
};

const Child = ({ handleClick }) =&amp;gt; {
  console.log("Child component re-rendered...");

  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;I am Child Component&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;Button inside child&amp;lt;/button&amp;gt;
    &amp;lt;/&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Both &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt; can be used to improve the performance of the React app by reducing unnecessary re-renders. At this point, most of us might be thinking that we should use these hooks for every function and component to improve performance but that is far from the truth. It's important to remember that &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt; comes with a cost of creating a memoized value or function and if the values that we are computing are not very expensive and don't change very often they cannot outweigh that cost.&lt;/p&gt;

&lt;p&gt;If the app is not performant, we should first try to find the underlying problem and fix it and then only use these hooks to improve the performance.&lt;/p&gt;

&lt;p&gt;If you liked this article, you might like my tweets too - &lt;a href="https://twitter.com/imvedanshmehra" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Show your support by giving a thumbs up to this article and share your thoughts in the comments.&lt;/p&gt;

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