<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Joel Mun on Medium]]></title>
        <description><![CDATA[Stories by Joel Mun on Medium]]></description>
        <link>https://medium.com/@9oelm?source=rss-412dae67af0b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*bdeCtIHMLI9S1iucSin2FQ.jpeg</url>
            <title>Stories by Joel Mun on Medium</title>
            <link>https://medium.com/@9oelm?source=rss-412dae67af0b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 08 Jun 2026 18:59:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@9oelm/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[elasticpwn: how to collect and analyse data from exposed Elasticsearch and Kibana instances]]></title>
            <link>https://9oelm.medium.com/elasticpwn-how-to-collect-and-analyse-data-from-exposed-elasticsearch-and-kibana-instances-c1951679fc7f?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/c1951679fc7f</guid>
            <category><![CDATA[infosec]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[bug-bounty]]></category>
            <category><![CDATA[elasticsearch]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Sun, 02 Jan 2022 14:08:02 GMT</pubDate>
            <atom:updated>2022-01-07T15:01:57.048Z</atom:updated>
            <content:encoded><![CDATA[<h3>Your Elasticsearch and Kibana instances are open, and that’s a real problem</h3><p>I have been doing some serious research on the public exposure of Elasticsearch and Kibana instances recently, and here are a few of the reports I made, found to be valid. I’ve been enjoying it so much:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/1*Im8-xaPKZZ-QPzQ9pZVVCQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/485/1*VPWTrhp7-cg5HvLht8PJFg.png" /></figure><p>But my enjoyment must be someone else’s pain. Literally thousands of Elasticsearch and Kibana instances are publicly exposed to the Internet. They are just up for grabs, and that is a really serious problem. Sometimes, even top renowned tech companies make mistakes about this, exposing their internal data exposed to the public. The nature of the data stored in these instances are sometimes quite sensitive and are never meant to be shared: be it phone numbers, email addresses, home addresses, names, credit card numbers, even (plaintext!) passwords, internal API logs, private user data specific to the service, and more and more. I’ve seen millions of such data through this journey, which I never expected.</p><p>I honestly feel so sad for the users who have their data exposed to the public and probably don’t even know about that because it’s the developers who make mistakes, not them. I saw data from huge game studios, shopping malls, and even some of the biggest banks. It’s awful and I wanted to help fix that.</p><p>But the staggering number of instances and <a href="https://www.elastic.co/blog/what-is-an-elasticsearch-index">indices</a> make it is somewhat difficult to find and collect <strong>interesting, or ‘useful’ data</strong> from them, which may lead to being awarded of bug bounties. To quickly gather data and filter useful and interesting ones, I decided to craft a tool that would automate removing lot of garbage data that nobody is interested in and help discover interesting data instead.</p><p>So here it is: <a href="https://github.com/9oelm/elasticpwn"><em>elasticpwn</em></a>.</p><h3>elasticpwn: a brief overview</h3><p>In this article, I will walk you through the general workflow of using elasticpwn. For the detailed explanation and full options, see <a href="https://github.com/9oelm/elasticpwn">README</a>.</p><p>Prerequisites: docker-compose, go^1.17, <a href="https://shodan.io">Shodan</a> or <a href="https://binaryedge.io">Binaryedge</a> account (free account available for both)</p><ol><li>Install the tool</li></ol><pre>go install github.com/9oelM/elasticpwn/elasticpwn@latest</pre><p>2. Get a list of URLs of publicly exposed Elasticsearch and Kibana instances from OSINT platforms like <a href="https://shodan.io">shodan.io</a> or <a href="https://binaryedge.io">binaryedge.io</a>. Here are some starter dorks:</p><p>binaryedge: find publicly exposed elasticsearch instances in the US</p><pre>elasticSearch AND country:&quot;US&quot; AND product:&quot;Elasticsearch REST API&quot;</pre><p>shodan: find publicly exposed elasticsearch instances, excluding false positives</p><pre>elasticsearch 200 -&quot;adminer_sid&quot; -&quot;MiniUPnPd&quot;</pre><p>3. Process the urls so that they are in the form of something like:</p><pre>123.123.123.123:80<br>124.124.124.124:443</pre><pre>.. and so on.</pre><p>and save them in a text file.</p><p>4. Launch a local mongo server (you don’t have to use mongodb, but for the sake of this tutorial, I will just use it — you can also use json output option)</p><pre>curl <a href="https://raw.githubusercontent.com/9oelM/elasticpwn/main/docker-compose-mongo-only.yml">https://raw.githubusercontent.com/9oelM/elasticpwn/main/docker-compose-mongo-only.yml</a> -o docker-compose-mongo-only.yml &amp;&amp; docker-compose -f docker-compose-mongo-only.yml up -d</pre><p>5. Run elasticpwn to collect data from the instances. This will collect and analyse all possible data from the instances with multiple threads.</p><pre>elasticpwn elasticsearch -f list_of_elasticsearch_instances.txt -murl mongodb://root:example@172.17.0.1:27017/ -of mongo -t 12</pre><p>6. Generate a report. This command will generate a directory called /report under CWD. There will be a lot of data, like really a lot, and you can’t just review them all unless there is some form of review system. So there goes the reason for the existence of report feature. By default, elasticpwn will do its best to find interesting data like email, password, api logs, etc using its built-in regex matching and show it in addition to basic information about an instance. Based on this data, you can skip uninteresting ones and only leave interesting ones.</p><pre>elasticpwn report generate -cn elasticsearch -murl mongodb://root:example@172.17.0.1:27017/</pre><p>7. View the report</p><pre>elasticpwn report view -d ./path-to-report -p 9999</pre><p>Here’s a sample report page containing information about a single Elasticsearch endpoint:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/0*aFpsB_I0GswlXbzE.png" /></figure><h3>elasticpwn: persisting your research</h3><p>elasticpwn also offers a way to store and retrieve the reviewed URLs, so that you don&#39;t have to review the same URLs again with the same report page. It often becomes very confusing because some instances are quite similar and the number of the instances is just too large.</p><p>All you need is a persistent mongo database and an additional installation of elasticpwn-backend.</p><ol><li>Generate the report with -dn option:</li></ol><pre># -dn should be the url where elasticpwn-backend will be hosted <br>elasticpwn report generate -cn elasticsearch -murl mongodb://root:example@172.17.0.1:27017/ -dn <a href="http://localhost:9292">http://localhost:9292</a></pre><p>2. Install elasticpwn-backend:</p><pre>go install github.com/9oelM/elasticpwn/report/elasticpwn-backend@latest</pre><p>3. Launch it. You need to specify your persistent mongodb URI as mongodbUri option:</p><pre>elasticpwn-backend -mongodbUri=mongodb+srv://username:pw@somewhere.mongodb.net/default-collection-name?retryWrites=true&amp;w=majority -databaseCollectionName=elasticsearch_reviewed_urls -databaseName elasticpwn -port 9292<br><br>2021/12/28 05:38:54 Connected to database<br>2021/12/28 05:38:54 Inserting<br>2021/12/28 05:38:54 Test url already created before<br>[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.<br><br>[GIN-debug] [WARNING] Running in &quot;debug&quot; mode. Switch to &quot;release&quot; mode in production.<br>- using env:   export GIN_MODE=release<br>- using code:  gin.SetMode(gin.ReleaseMode)<br><br>[GIN-debug] GET    /ping                     --&gt; main.PingHandler (4 handlers)<br>[GIN-debug] GET    /urls                     --&gt; main.GetUrlsHandlerGenerator.func1 (4 handlers)<br>[GIN-debug] POST   /urls                     --&gt; main.PostUrlsHandlerGenerator.func1 (4 handlers)<br>[GIN-debug] DELETE /urls                     --&gt; main.DeleteUrlsHandlerGenerator.func1 (4 handlers)<br>[GIN-debug] Listening and serving HTTP on 0.0.0.0:9292</pre><p>4. With the server turned on, view the report (probably in another shell):</p><pre>elasticpwn report view -d ./path-to-report -p 9999</pre><p>Then, the report should be available, and each time you hit the ‘review’ button either with the keyboard shortcut or a click, the URL will be saved in the database for you to come back later or filter out duplicates later. If you are consistently generating report — say per week — then persistent database probably the answer.</p><h3>Securing your Elastic stack</h3><p>These are some really minimal steps to get your Elastic stack secured:</p><ul><li>set xpack.security.enabled as true if you are running an old version of the Elastic stack. One really good news is that this is going to be true by default in the newest versions. This will help protect lots of instances from being exposed to the world:</li></ul><blockquote>Currently, security features are disabled when operating on a basic or trial license when xpack.security.enabled has not been explicitly set to true. This behavior is now deprecated. In version 8.0.0, security features will be enabled by default for all licenses, unless explicitly disabled (by setting xpack.security.enabled to false).</blockquote><ul><li>set password: bin/elasticsearch-setup-passwords interactive</li><li>use WWW-Authenticate header to restrict access</li><li>put the instances inside the private network and use VPN</li><li>and so much more…</li></ul><p>Elastic has <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/secure-cluster.html">a detailed documentation</a> on security, so make sure you check it out if you are the guy who manages the Elastic stack in the company.</p><h3>Conclusion</h3><p>So far, we have looked at:</p><ul><li>the problem of data exposure from numerous Elasticsearch and Kibana instances</li><li>how elasticpwn helps detect and analyse the exposed data</li><li>simple ways to secure the Elastic stack</li></ul><p>Thank you, and your feedback is always appreciated.</p><p><em>Originally published at </em><a href="https://9oelm.github.io/2022-01-02--elasticpwn-how-to-find-and-collect-data-from-exposed-elasticsearch-and-kibana-instances/">https://9oelm.github.io/2022-01-02--elasticpwn-how-to-find-and-collect-data-from-exposed-elasticsearch-and-kibana-instances/</a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c1951679fc7f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Complete End-to-end Guide for Developing Dockerized Lambda in Typescript, Terraform and SAM CLI]]></title>
            <link>https://medium.com/geekculture/complete-end-to-end-guide-for-developing-dockerized-lambda-in-typescript-terraform-and-sam-cli-ecdea1c6e72c?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/ecdea1c6e72c</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[aws-lambda]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[infrastructure]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Sun, 21 Mar 2021 14:38:25 GMT</pubDate>
            <atom:updated>2021-03-27T06:48:38.951Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Kf5kO7xWNg0mhRx-Wdx8zg.png" /><figcaption>Docker + TS + Terraform + Lambda + ECR + SAM CLI = 💚</figcaption></figure><p>This is a full guide to setup, develop and deploy a backend app with <a href="https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/">a recently released container image feature for lambda on AWS</a>.</p><p>Needless to say, if you are a great fan of Docker, you would know how amazing it is. What you test on local is what you get when you deploy it, at least at the container level.</p><p>Since this feature is quite new, there have been <strong>lots of rabbit holes</strong> I fell into, and I’m sure others will too, so I will break every piece of rabbit hole down so that nobody gets trapped into it. This guide starts from the real basics like making a user or setting up terraform, so feel free to skip to the section you need.</p><h3>Reason to use Terraform and SAM CLI together</h3><p>Well, it seems that Terraform supports building a Docker image and deploying it to ECR out of the box, but after lots of digging, I noticed that things would get simpler if I just build docker image in another pipeline and deploy it with a few lines of shell script. So Terraform will used to define resources excluding the build and deployment process. There’s no problem with that.</p><p>And, what SAM CLI? Terraform cannot replace SAM CLI and vice versa. SAM cli is useful in developing local lambdas because it automatically configures endpoints for each lambda and greatly removes barriers to the initial setup. Since lambda functions are ‘special’ in the way that they only get ‘booted up and called’ when they are invoked (unlike EC2 or Fargate), just doing ts-node my-lambda.ts would not make it work. Of course there are many other solutions to this matter (such as sls) but in this guide I will just use SAM CLI. But for many reasons SAM makes me want to use other better solutions if any... The reason follows right below.</p><p><em>Disclaimer for the people who are looking for how to ‘</em><strong><em>hot-reload</em></strong><em>’ docker container for typescript or javascript based lambda</em>: it won’t work smoothly as of now. The best bet is to use nodemon to watch a certain directory to trigger sam build every single time, and in another shell launch sam local start-api. It works as expected, but the current problem I see from here is that every single time it sam builds, it would make another Docker image and another and so on, so there will be many useless dangling images stacked up in your drive, which you will need to delete manually because SAM CLI does not support passing in a argument that&#39;s equivalent to docker run --rm. Anyways that&#39;s the story, so this is the reason I might want to try some other solutions. <a href="https://github.com/aws/aws-sam-cli/issues/921">More on this on the relevant issue on Github</a>. Please let me know if any of you had a good experience with sls because I haven&#39;t used it much yet.</p><p>Ok. Now let’s write some code.</p><h3>Setup AWS for Terraform</h3><p>First, make sure that you’ve installed and authorized on your AWS CLI. Installing AWS CLI is kind of out of scope here, so <a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html">please follow the guide on AWS</a>.</p><p>After successful installation, run:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f4ba6df18ddfddcd32e058a8e1f9a00d/href">https://medium.com/media/f4ba6df18ddfddcd32e058a8e1f9a00d/href</a></iframe><p>You will be prompted to enter Access Key ID and Secret Access Key. Depending on your situation, there are different ways of how you can handle this, but for the sake of simplicity we can make one user (from AWS console. You will probably only use it for ‘Programmatic access’) that would have these policies for applying Terraform codes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1017/1*8h7lS3_Pstwq-tauo5Dowg.png" /><figcaption>Add user</figcaption></figure><p>This one for setting S3 bucket as a backend:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5a8fc5f67e883bd8494365b920f76ccf/href">https://medium.com/media/5a8fc5f67e883bd8494365b920f76ccf/href</a></iframe><p>And this one for locking the state:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8aa06198a0155934e1bad2cebcd64028/href">https://medium.com/media/8aa06198a0155934e1bad2cebcd64028/href</a></iframe><p>And the next one is quite tricky; because we will temporarily enable permissions related to managing IAM because we will first need to make a role from which we could assumeRole whenever we try to plan and apply our IaC.</p><p>For now we can just go onto AWS console and make this policy:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2da951b9d997a2dc3297c976c307ba0d/href">https://medium.com/media/2da951b9d997a2dc3297c976c307ba0d/href</a></iframe><p>Make sure you will need to narrow down to specific actions and resources used after everything is done (for production usage).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JnoOMdtXrMg1OIG0Lqj30A.png" /><figcaption>Create policy</figcaption></figure><p>Now, now that you’ve made three distinct policies (or all in one, depending on your preferences), attach them to the user that you’ve just crated for running aws configure.</p><h3>Setup Terraform</h3><p>If you haven’t already, <a href="https://learn.hashicorp.com/tutorials/terraform/install-cli">install terraform by following an instruction from the official website</a>. Just download the binary and move it to the bin folder.</p><p>Now verify version of terraform</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6e1d349d1377f20d301bb71ae7d98807/href">https://medium.com/media/6e1d349d1377f20d301bb71ae7d98807/href</a></iframe><p>And then make main.tf file in your project directory (I personally put it into IaC folder because there will another folder for the &#39;real&#39; .ts codes for the backend):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/637711f1fabc4a225eca34fa07f0143a/href">https://medium.com/media/637711f1fabc4a225eca34fa07f0143a/href</a></iframe><p>Now, run terraform init:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ed1ba56883103fb156e635f6c50df82f/href">https://medium.com/media/ed1ba56883103fb156e635f6c50df82f/href</a></iframe><p>Then, we will need to add s3 backend and state locking. But before then, make a table on Dynamodb and also a bucket on S3, each for hosting IaC backend and locking the state.</p><p>Now we will need to add more to the policy on DynamoDB we created because we want to create a table:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/152f4d49f06b98861b72081c9395374e/href">https://medium.com/media/152f4d49f06b98861b72081c9395374e/href</a></iframe><p>Then you could write this code (by the way, it may be a good idea to put this below IaC in a different general-purpose repository because the current repository is meant to be only used for lambda-related resouces. But for the sake of this article I will just write it away here):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2db6b3329269661d05795fdadf27a24c/href">https://medium.com/media/2db6b3329269661d05795fdadf27a24c/href</a></iframe><p>And then, also add S3 backend (you will need to add relevant IAM policies too here, but since we know how to do it, I will cut the explanation):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fa86770f27a2498411c0148ef433d42c/href">https://medium.com/media/fa86770f27a2498411c0148ef433d42c/href</a></iframe><p>Now, run terraform apply, verify the changes, and enter yes. DynamoDB table and S3 Bucket should have been created. Here&#39;s the code so far:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f64a7c35dceb33d018a7bab4d2b41161/href">https://medium.com/media/f64a7c35dceb33d018a7bab4d2b41161/href</a></iframe><p>Now, add s3 backend and state lock:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a3404cf4236aa8f407a8a18497d6eea/href">https://medium.com/media/3a3404cf4236aa8f407a8a18497d6eea/href</a></iframe><p>We are also going to use Docker provider, so add that too:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/951de6ac3d4da7b596b8f59593dd31af/href">https://medium.com/media/951de6ac3d4da7b596b8f59593dd31af/href</a></iframe><p>Now because you’ve added a backend and another provider, we will need to run terraform init again, and then terraform apply. Run it.</p><h3>Setting up lambda</h3><p>Now we will need to develop lambda on the local machine. Install SAM CLI:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e466ec9e81bb0f3383f1c56d34ef483c/href">https://medium.com/media/e466ec9e81bb0f3383f1c56d34ef483c/href</a></iframe><p>Note that the outdated versions would not support running Docker containers, so make sure that your version is the latest.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fc050ff3aa33fe5752673bd4fd690fd0/href">https://medium.com/media/fc050ff3aa33fe5752673bd4fd690fd0/href</a></iframe><p>Now, we won’t run sam --init, because it will make it difficult to make the server into a monorepo structure. The reason that we will want to make it into a monorepo is that it will make it much easier to propery dockerize every single lambda and deploy it with dependencies that each of them only require to have. Instead we will use <em>lerna</em> to initialize the server folder.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/752ee156b894028347969192b7332a68/href">https://medium.com/media/752ee156b894028347969192b7332a68/href</a></iframe><p>And as usual:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fcb5c7537c73f323d277867c32e0a207/href">https://medium.com/media/fcb5c7537c73f323d277867c32e0a207/href</a></iframe><p>Then it will give you this layout:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/940acf19a001fa7137cfb3288f6f3be3/href">https://medium.com/media/940acf19a001fa7137cfb3288f6f3be3/href</a></iframe><p>Then, add your first function package. For the sake of this example, let’s assume that we want to make a REST API, composed of many lambdas, each returning ‘hello’ as a response in different languages (which is totally useless in reality, but at least useful here). Our first lambda will be an English one.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b578c4d2fd45b385e92fdf223d1736aa/href">https://medium.com/media/b578c4d2fd45b385e92fdf223d1736aa/href</a></iframe><p>Now the directory structure will look like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/493e5bfc806ea9a962f3b753762a57c2/href">https://medium.com/media/493e5bfc806ea9a962f3b753762a57c2/href</a></iframe><p>Now, under server, we will need to add some utils to build and invoke the function locally. Add modify the server/package.json as follows and of course, run npm i again:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/22ce80a56475a1e3e7bfddbb267f4b48/href">https://medium.com/media/22ce80a56475a1e3e7bfddbb267f4b48/href</a></iframe><p>To add some explanation to what we are trying to do: these devDependencies are going to be package-wide dependencies. These are not specific to any one of the functions that we are going to build; They will help in tooling general stuffs. That&#39;s what we put them here.</p><p>Dependencies:</p><ul><li>@types/node: we will need this to give proper type definitions for &#39;built-in node&#39; modules like fs or path.</li><li>concurrently: just a script runner.</li><li>lerna: you know it.</li><li>nodemon: this will help us watch a directory and build Docker image again.</li></ul><p>Scripts:</p><p>Now, you need to create template.yml for SAM cli to consume and run what we want to run.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/967bf89e76802ace11f75cba910512a3/href">https://medium.com/media/967bf89e76802ace11f75cba910512a3/href</a></iframe><p>We won’t be able to run sam build or sam local start-api yet, because we still need to setup Dockerfile and ECR repository.</p><p>So far we have added template.yml for running SAM CLI:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/84cf4dc848206c58cf838df42b091050/href">https://medium.com/media/84cf4dc848206c58cf838df42b091050/href</a></iframe><p>Now we will add Dockerfile in packages/hello/.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6302b5f0456c6d91fd1aae0945eac245/href">https://medium.com/media/6302b5f0456c6d91fd1aae0945eac245/href</a></iframe><p>This will be the content for Dockerfile:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cbdf0bf342dd01adba7d6a102dcd85bf/href">https://medium.com/media/cbdf0bf342dd01adba7d6a102dcd85bf/href</a></iframe><p>To go through it line by line:</p><ul><li>amazon/aws-lambda-nodejs:14 is the official amazon image for lambda. Current LTS of nodejs is 14, so we are using this. AS builder is related to multi-stage builds in Docker; it helps reduce the final Docker image size. Basically in this builder stage, we will only build the output to be included in the final image, and any dependencies installed in this step won&#39;t be included in the final output image.</li><li>WORKDIR /usr/app: inside the docker image, set the working directory as /usr/app. There isn&#39;t any app folder in a normal docker image, so it will make app directory. We will put the compiled js code there.</li><li>COPY package*.json tsconfig.json ./: we need these files for compiling typescript into javascriptt files.</li><li>npm install: it will install dependencies.</li><li>npm run build: it will compile typescript code into js.</li><li>RUN ls -la # for debugging: it is merely for debugging. While building, docker will output what&#39;s inside there at that time, for you to verify if you are doing what you intended to do.</li><li>FROM amazon/aws-lambda-nodejs:14: this is the second build stage in Docker. All outputs from the previous stage will be discarded in this stage unless explicitly specified to be included.</li><li>RUN npm install --only=prod: it will only install dependencies but devDepdencies.</li><li>COPY --from=builder /usr/app/lib /usr/app/lib: it explicitly refers to the previous builder stage to copy whatever that was inside /usr/app/lib to the current /usr/app/lib. In this case, it will copy all compiled javascript code.</li><li>CMD [ &quot;/usr/app/lib/index.handler&quot; ]: the command should be path-to-lambda-handler-without-extension.handler. That&#39;s just how it works.</li></ul><p>Now we’ve added a Dockerfile. Now let’s setup basic environment for lambda:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a769c8e091d9a1e4d35e305147e66bc/href">https://medium.com/media/2a769c8e091d9a1e4d35e305147e66bc/href</a></iframe><p>You will need to modify tsconfig to use modern javascript features; Most prominently, add the following. This will allow you to use Promise API. I recommend turning other options too, especially those related to strict-type checking:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a57c559c9da298021188d0f715a85c1e/href">https://medium.com/media/a57c559c9da298021188d0f715a85c1e/href</a></iframe><p>Modify packages/hello/package.json too. Be noted that any dependencies you add to be included in the final, compiled output code (javascript) will need to be added to dependencies, not devDependencies:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/692d5cc6d62aa67a9faa3efaed686882/href">https://medium.com/media/692d5cc6d62aa67a9faa3efaed686882/href</a></iframe><p>Now, add a really simple lambda:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/37a76fb61a6b5a84f7146b2ffeb80066/href">https://medium.com/media/37a76fb61a6b5a84f7146b2ffeb80066/href</a></iframe><p>So far, we have created these:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a55aacd80247b1548eb90561e03abde6/href">https://medium.com/media/a55aacd80247b1548eb90561e03abde6/href</a></iframe><p>Now, create nodemon.json under server/ to watch and build files:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/59998268abb99917e30eb7ce826563c2/href">https://medium.com/media/59998268abb99917e30eb7ce826563c2/href</a></iframe><p>After creating nodemon.json, you can start running npm run watch or npm start. It would do two things: build Dockerfile as you make any changes under packages/ directory, and host a local endpoint for the lambda. It will be similar to hot-reload although it seems more like a hack; you won&#39;t need to cancel and run sam local start-api again once you make a change. If it does not work, try again after creating ECR first.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f94d9427655e3ed6f60a20b899de6523/href">https://medium.com/media/f94d9427655e3ed6f60a20b899de6523/href</a></iframe><p>Oh, and you can delete __tests__ and lib/hello.js because we are not using them. Anyways, now we are kind of ready to build this function into a docker image. Let&#39;s try it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/71d43e110352b803798696061fa1f888/href">https://medium.com/media/71d43e110352b803798696061fa1f888/href</a></iframe><p>Everything’s cool, docker build succeeded. You can try running the image and test the request:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lp7wPwEFJvjJ0s9PZ_y71w.png" /><figcaption>Invoking lambda locally</figcaption></figure><p>This is where SAM CLI should start to come in. But before then, we will need to make a ECR repository with terraform. Let’s go back to terraform for a while.</p><h3>Back to Terraform: assuming role and ECR</h3><p>Now, we will need to create a role first because we will relay on that role to get required permissions to create whatever resource we want to. This is called ‘assuming a role’, and the reason why it’s deemed to be a good practice is that you won’t have to create multiple credentials (probably multiple users) to do certain thing that requires permissions. Instead, you <em>borrow</em> the permission for the period of time when you plan and apply the changes in the resources.</p><p>So how do we do it? First, let’s create hello_role.tf:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bd2f830b7cb8d1acba27e8e2b77b232b/href">https://medium.com/media/bd2f830b7cb8d1acba27e8e2b77b232b/href</a></iframe><p>For this article, we won’t be diving deep into specific policies, so we will just allow almost all resources without specifying them in detail. For real-world usage, you will have to define exact statements giving just the right permissions.</p><p>What we are doing here, essentially, is that we are allowing localtf user to assume the role of hello_role that possesses all policies to run the hello server stack. This is called &#39;creating a trust relationship&#39; (you will see this if you do this process on AWS). This way, localtf won&#39;t always have to hold all permissions it needs. It only acquires them only when needed (i.e. deploying)</p><p>Once you are done writing hello_role.tf, run terraform apply to make changes.</p><p>Now, go back to main.tf and add:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d31b3879670cf5414db49d8e95cea12e/href">https://medium.com/media/d31b3879670cf5414db49d8e95cea12e/href</a></iframe><p>Once you add assume_role, now you can create any resources you want, using the permissions given by that role. Let&#39;s now make an ECR repository. Make ecr.tf:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b07f77df8679e9b7d31548036f5a8a1b/href">https://medium.com/media/b07f77df8679e9b7d31548036f5a8a1b/href</a></iframe><p>Run apply and terraform will soon make ECR.</p><h3>Building and pushing the image to ECR</h3><p>Now that we’ve made an ECR, we can go back to our server and write a little script to login, build and push the image of the lambda we are writing.</p><p>It’s pretty much straightforward; just get your AWS cli ready for using; and authenticate to be able to use ECR from Docker CLI:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/20ecb153bd27b8845a5ca611e40f10b6/href">https://medium.com/media/20ecb153bd27b8845a5ca611e40f10b6/href</a></iframe><p>Next, tag your Docker image as latest and separate timestamp at the time of the build, so that latest tag will always be the latest built image, and then another image will remain for the record, which you can use later to revert back or do other things in some cases.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/018992e53d4329b0588692d7a6a2cd8c/href">https://medium.com/media/018992e53d4329b0588692d7a6a2cd8c/href</a></iframe><p>Now, you can test it out yourself as such:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b1fc57a1fa982bb6f57ea3aacdcdd7ce/href">https://medium.com/media/b1fc57a1fa982bb6f57ea3aacdcdd7ce/href</a></iframe><p>After this, you will be able to see on AWS ECR:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rvBqLXNxzOoQw-7t-UK9CQ.png" /><figcaption>Images on ECR</figcaption></figure><p>as you can see, the images are going to be tagged by timestamp, and the latest built image will be always tagged as latest, and you are going to reference this tag in Terraform to apply newly built Docker image to lambda.</p><p>So far, we’ve made changes like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fddf318985107fe74cfb1e96d9d41862/href">https://medium.com/media/fddf318985107fe74cfb1e96d9d41862/href</a></iframe><p>Now the majority of the prepartion is done, so we can move onto creating actual lambda and API gateway.</p><p>First, the most important part: you want to create lambda itself from Docker.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/481791a5f89981b7ed257330a68fedf9/href">https://medium.com/media/481791a5f89981b7ed257330a68fedf9/href</a></iframe><p>There is already a module just made for this, so use it to make lambda. Once you are done, apply the changes.</p><p>The key here is that you are going to reference an image URI from ECR where the tag is the latest. If you have previously built and pushed a new docker image, the hash of the image is going to be different, thus causing a redeployment of the lambda function. Otherwise it has no idea if the docker image is new or not.</p><p>Again, after running the change, you can see the lambda on AWS console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1f0BKVIw2LqlpdjJr-jltw.png" /><figcaption>Check lambda created on AWS console #0</figcaption></figure><p>as you can see, compared to other lambdas, it has the package type of ‘Image’, which means it’s not from a Zip, but a Docker image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iIzM6deuorH5G1rhLbkXPA.png" /><figcaption>Check lambda created on AWS console #1</figcaption></figure><p>You should be able to see the image URI (including the hash) of the image at the bottom of the information about lambda. If you click on that image URI, you will be navigated to the latest image on ECR that you just built and pushed.</p><p>Now, you will be able to test lambda on AWS Lambda console, but what we want in the end is something like sending GET /hello to a certain domain and receiving a response. To be able to do that, we need to setup API Gateway.</p><p>For this example, we will setup a domain at api.hello.com.</p><p>Here’s how:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/308ba236cafe308f4bdad6bb4a087168/href">https://medium.com/media/308ba236cafe308f4bdad6bb4a087168/href</a></iframe><p>I will explain the code one by one.</p><p>aws_api_gateway_rest_api will create a REST api. It usually does not include a single endpoint; it usually contains multiple, like: api.hello.co/hello, api.hello.co/bonjour, api.hello.co/nihao, and so on. On AWS, it is equivalent to a single row in APIs tab:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*34jHww2ycJsPvy9W8gg2zg.png" /><figcaption>APIs tab</figcaption></figure><p>aws_api_gateway_resource: to put it very simply, you can think of this as a single API endpoint that has not yet been deployed. In this case we create a single endpoint ending with /hello.</p><p>In the below example, we have created two different resources with OPTIONS and POST, to the same path (hidden by black overlay). We will talk about creating OPTIONS resource to handle preflight requests later. For now, it would suffice to know that creating a REST resource means creating a certain endpoint.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vGCw0WBC_zialnzEcGPDGA.png" /><figcaption>REST resource</figcaption></figure><p>aws_api_gateway_method: Now, you want to create a REST method for that resource. Our /hello endpoint will just require no auth (out of scope of this article), and be a GET method.</p><p>aws_lambda_permission: By default, there&#39;s no permission for API gateway to invoke lambda function. So we are just granting a permission to it so that it can be executed.</p><p>aws_api_gateway_integration: API gateway supports transforming (filtering, preprocessing, ...) a request before it reaches client or a response from the client before it reaches the actual lambda. We are not doing any special things here for this example, but you may want to use it in the future. For more, <a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-integration-settings.html">read relevant AWS docs</a>.</p><p>aws_api_gateway_stage: API gateway supports separating API into different stages out of the box. You should use this to separate your API across production, staging and development environments. For now, we will only make a stage for current terraform workspace, which is assumed to be dev across all examples in this article. Once you apply your changes, you are going to be able to see this on your AWS console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zzvoUWbqYo1Ki5zEvY-PyQ.png" /></figure><p>aws_api_gateway_deployment: This is equivalent to clicking on &#39;Deploy API&#39; on AWS console.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lD8jW0DHHbis24FcJHTMgw.png" /></figure><p>Once resources are created in API gateway, they <em>must</em> be deployed in order to be reachable from external clients. One little problematic thing is redeployment; Even if you make a change to your REST API resources, it will not get deployed if redeployment argument does not change. There are mainly two ways of getting around this:</p><ol><li>Use timestamp() to trigger redeployment for every single apply. Using this approach, lambda may be down for few seconds while redeployment. But it is for sure that it always deploys, so I would just go with this one if my service does not handle many users.</li><li>Use md5(file(&quot;api_gateway.tf&quot;)) to trigger redeployment whenever this file changes. But you need to always make sure that EVERYTHING related to API Gateway deployment only stays inside this file.</li></ol><p>Ok. So far we have set up lambda and basic API Gateway configurations. Right now, you can test your API on Postman like this: first, go to AWS API Gateway console, and find a specific endpoint that is deployed to a certain stage. There should be an ‘Invoke URL’ at the top of the page.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UtYBzOnfz544gVeHB_Bjcg.png" /><figcaption>Invoke URL</figcaption></figure><p>Now, open up Postman, and</p><ol><li>Insert your invoke URL</li><li>Click ‘Authorization’, and choose the type ‘AWS Signature’, and enter AccessKey and SecretKey. These keys should be coming from one of user&#39;s credentials from AWS IAM Console. If you do not have one specialized for calling an API set up with lambda and API gateway from local environment, make one user for that and get the keys.</li><li>Insert your AWS Region.</li><li>If your API requests any more query parameters or body, insert them.</li><li>Click send, then it should work.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T7modWjBW542zHw6hdlloA.png" /><figcaption>Testing ‘Invoke URL’ on Postman</figcaption></figure><p>If you do not provide AWS Credentials in your request header, it won’t work, because so far your API can be only used by IAM users known to the API gateway, and if you are just sending a request from your local computer without providing any access and secret keys, it won’t know it’s you. To make it work even without providing credentials for any public APIs intended to be exposed to client applications, you should now configure <strong>custom domain</strong>.</p><p>So far we have made changes to make lambda and API Gateway resources. The list of files we should have by now is the following.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/52dcd972a906928cef7e10e9f0908e6d/href">https://medium.com/media/52dcd972a906928cef7e10e9f0908e6d/href</a></iframe><p>Next, we will see how to create a custom domain and relate that domain to the REST API we just made.</p><h3>Creating Terraform resources for custom domain</h3><p>Now, the problem is that we have the API, but it’s not callable from any external client applications, which is a common case for many projects. So we want to register a domain first to represent our endpoints.</p><p>Before making a change for custom domain, we need to setup another AWS provider because we will need to use us-east-1 region for Edge-optimized custom domain name ( <a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-edge-optimized-custom-domain-name.html">that&#39;s the only region that supports creating an ACM certificate for Edge-optimized custom domain name</a>).</p><p>There are two choices available for an API endpoint: 1. edge; 2. regional. If your endpoint should be accessed by worldwide clients, use edge; if your endpoint is specifically confined to be used in one specific region in the world, use regional. If you don’t know what to do, it totally safe to go with edge for now. First, add another aws provider:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a541731af856d3d72534c06e1020e814/href">https://medium.com/media/a541731af856d3d72534c06e1020e814/href</a></iframe><p>Then, you write the actual code to make a certificate and custom domain.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2fb0baeaa0f7653ef1c518d55c96da99/href">https://medium.com/media/2fb0baeaa0f7653ef1c518d55c96da99/href</a></iframe><p>Make sure you get the existing hosted zone ID (or any other zone ID that you intend to use) from AWS Route53 Console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UuS6DvmywS3hGw6spdo-zg.png" /><figcaption>Route53</figcaption></figure><p>Use that ID to create Route53 Record for the custom domain name.</p><p>After you apply your change, you will be able to see ACM certificate being created on AWS Certificate Manager:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7Jd6QfkrmZF5wBoqtwXang.png" /><figcaption>AWS Certificate Manager</figcaption></figure><p>Just make sure you verified the status to be ‘Issued’ and the validation status to be ‘success’. You may need to wait for several minutes before this completes. Also, if your certificate is not showing up, make sure that you are on us-east-1, not anywhere else.</p><p>After you are done with this, now you can go back to API Gateway again, and configure custom domain. Now that you’ve registered a domain, you can see it right up from API Gateway console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oLfhXkNz458YvGyHK0bG8A.png" /></figure><p>In the certificate dropdown, you should be able to see the domain that you have just created. Do not make create domain name there on the console. Now come back to terraform and let’s write the equivalent code for that.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/50c2dfb2c4edad5b9c43f645175e5cce/href">https://medium.com/media/50c2dfb2c4edad5b9c43f645175e5cce/href</a></iframe><p>You are just going to fill out the options that you just saw from the API Gateway console. Just fill out the relevant info about certificate, domain name, and endpoint config.</p><p>Now, this is important: you need to create another Route53 Record to map your custom domain to cloudfront. Once you create your custom domain, AWS creates ‘API Gateway domain name’, circled with red in the below picture:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ccGAaXKZ-fae4eyTdYMvZQ.png" /><figcaption>API Gateway domain name</figcaption></figure><p>You need to route the traffic to api.hello.com to this API Gateway domain name (an example of an API Gateway domain name would be asdfasdfasdf.cloudfront.net as long as you are using EDGE). That&#39;s what we are doing with aws_route53_record.custom_domain_to_cloudfront. Otherwise, the response to your API will keep showing some weird errors that are really hard to guess the causes of. I found AWS really lacking a documentation on this part, so please be advised on this one. <strong>You need to create another Route53 Record</strong>.</p><p>You will be able to verify by entering Route53 console and looking for api.hello.com. It should appear as the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/799/1*iunic1rx_HpDGyT8SrHp6A.png" /><figcaption>Route53 record for api.hello.com to asfasdfasdf.cloudfront.net</figcaption></figure><p>After that, you don’t have to do many things; just add base path mapping resource, in api_gateway.tf. Even if you do not have an additional trailing path to your endpoint, you <em>must</em> create a base path mapping. Otherwise your API won&#39;t be exposed to the public.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a31494b71590e1ac0bf95d78625bab01/href">https://medium.com/media/a31494b71590e1ac0bf95d78625bab01/href</a></iframe><p>After applying this change, verify that your API mapping has been created:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G2TBy_LYWmMM5lmVSuu4IQ.png" /><figcaption>API mapping on API Gateway</figcaption></figure><p>Now, you can go back to Postman, and test your api by requesting GET api.hello.com/hello. What may be confusing here is that you are not adding any path in base path mapping. If you add hello as a path, your API endpoint will be configured as api.hello.com/hello/hello, which is obviously not what we want. So do not add any path mapping if you already have configured your path in aws_api_gateway_resource). Anyways, request and response to the API endpoint should work as expected if everything has been setup correctly so far.</p><h3><strong>Enabling OPTIONS (preflight request)</strong></h3><p>Now, our client application, of course, is not Postman, so usually clients will request OPTIONS api.hello.com/hello first, and then request GET api.hello.com/hello, if they intend to send CORS requests, which is a very common case (<a href="https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request">read more about that from MDN docs</a>)</p><p>If you have not done anything related to handling OPTIONS request, it’s very likely that you will get some error in your client application, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P9gbEU3XKVJMXbfj4UOVUQ.png" /><figcaption>Image from <a href="https://stackoverflow.com/questions/59909987/aws-api-gateway-403-forbidden-response-to-preflight-options-request">https://stackoverflow.com/questions/59909987/aws-api-gateway-403-forbidden-response-to-preflight-options-request</a></figcaption></figure><p>So let’s do it! There’s already a <a href="https://github.com/squidfunk/terraform-aws-api-gateway-enable-cors">handy module written by a great dev</a>, so we will just use that:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3ff9a8e97ad348f6d570b4bf0e904383/href">https://medium.com/media/3ff9a8e97ad348f6d570b4bf0e904383/href</a></iframe><p>Note that if you have any custom headers, you must define it in your config. Next, verify that OPTIONS requests are now allowed on the console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/559/1*9ygAvO4BAuio8wE89AsI-Q.png" /></figure><p>Also, you will need to change your lambda’s response header too. Just adding Access-Control-Allow-Origin&quot;: &quot;*&quot; will work:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1564c2704ee2ab9ba5835e3b261a4def/href">https://medium.com/media/1564c2704ee2ab9ba5835e3b261a4def/href</a></iframe><p>Now, apply the changes, and go back to your client app and retry the request. It should be working.</p><h3>Summing up</h3><p>If you have followed everything, you will have created these files:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/abd28b47798097db5294562f7f337792/href">https://medium.com/media/abd28b47798097db5294562f7f337792/href</a></iframe><p>So far, we have looked at how to setup, develop and deploy a dockerized lambda application with Typescript, Terraform and SAM CLI. There are tonnes of things to cover on lambda.. maybe next time, it will be on using resources inside VPC from lambda. I hope you enjoyed this and found some valuable insights. Thank you.</p><p><em>Originally published at </em><a href="https://9oelm.github.io/2021-03-13-complete-end-to-end-guide-for-developing-dockerized-lambda-with-typescript-terraform-and-SAM-cli/"><em>https://9oelm.github.io/2021-03-13-complete-end-to-end-guide-for-developing-dockerized-lambda-with-typescript-terraform-and-SAM-cli/</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ecdea1c6e72c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/geekculture/complete-end-to-end-guide-for-developing-dockerized-lambda-in-typescript-terraform-and-sam-cli-ecdea1c6e72c">Complete End-to-end Guide for Developing Dockerized Lambda in Typescript, Terraform and SAM CLI</a> was originally published in <a href="https://medium.com/geekculture">Geek Culture</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Make useSelector Not a Disaster]]></title>
            <link>https://medium.com/swlh/how-to-make-useselector-not-a-disaster-6fdd1c558fd3?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/6fdd1c558fd3</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Sun, 13 Sep 2020 15:25:52 GMT</pubDate>
            <atom:updated>2020-09-14T10:01:15.750Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wPjCSsOGoRMkZs_8OlUeRQ.png" /></figure><p><em>Disclaimer</em>: We will focus on useSelector itself in this article, rather than third-party libraries like reselect, because it&#39;s out of the scope of the article.</p><h3>How was it like before?</h3><p>Now, before talking about useSelector, we need to know some background. Let&#39;s go back to pre-function component era, where all we needed to care about where the props. Not so much you needed to do. Choices were PureComponent and shouldComponentUpdate. Nothing else. Like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1963070a10f029e547c001c7a410c2d4/href">https://medium.com/media/1963070a10f029e547c001c7a410c2d4/href</a></iframe><p>Right. So if you make such component, this component is only going to update when shouldShowRed is changed. Otherwise, it is going to stay still even if its parent renders for some reason. It goes the same for shouldComponentUpdate; It just gives you additional tooling to specify your own method of telling the component when to update.</p><h3>Using it with Redux?</h3><p>Again, using the component with redux was pretty straightforward too. Just create a container and pass states and dispatches (I didn’t write any mapDispatchToProps for the sake of simplicity) mapped as props:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0d147e66e0819faedb5368e5fcd17aee/href">https://medium.com/media/0d147e66e0819faedb5368e5fcd17aee/href</a></iframe><p>Right. Let’s assume that we have RootReduxState as we have seen from the code above. And this is just going to work so well. Nothing difficult here. SomeDiv will keep being efficient at its best because PureComponent is working well. But how should we precisely port this example to a function component?</p><h3>Function component</h3><p>Well, it’s easy. Just use useSelector, Right?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/38d63d838e94a677a4e76826af1a3608/href">https://medium.com/media/38d63d838e94a677a4e76826af1a3608/href</a></iframe><p>Perfect. But what if you need more than just shouldShowRed? The moment you start to get more than one thing from useSelector (which is a very normal case), you are going to need additional optimization efforts with appropriate knowledge.</p><p>If we were to use shouldShowGreen too, we could choose:</p><p><strong>Option 1</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5ae4cbf4cd84bc7caf4e648f59e3b97a/href">https://medium.com/media/5ae4cbf4cd84bc7caf4e648f59e3b97a/href</a></iframe><p>Or, we could:</p><p><strong>Option 2</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9f368abd56d721db8304fdfc5c58f18e/href">https://medium.com/media/9f368abd56d721db8304fdfc5c58f18e/href</a></iframe><p>Alternatively:</p><p><strong>Option 3</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3f793ad89705629670b82854179c81ba/href">https://medium.com/media/3f793ad89705629670b82854179c81ba/href</a></iframe><p>Or, just a small variant..</p><p><strong>Option 4</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f95535ca664b53308c0216c9ca74636/href">https://medium.com/media/8f95535ca664b53308c0216c9ca74636/href</a></iframe><h3>useSelector forces re-renders</h3><p>Which method have you been using? Whichever one you are using, you should be able to give reasons! Now, before having a look at each option, let’s go back to useSelector and see what it does.</p><p>So let me bring the most important thing to the table immediately: useSelector forces re-render of your component. It&#39;s not a prop, but it can still make your component re-render. Really? Yes. Let&#39;s look at <a href="https://react-redux.js.org/api/hooks#useselector">the offical documentation</a>:</p><blockquote><em>When an action is dispatched, useSelector() will do a reference comparison of the previous selector result value and the current result value. </em><strong><em>If they are different, the component will be forced to re-render</em></strong><em>. If they are the same, the component will not re-render.</em></blockquote><p>So how do you judge if they are different? By running strict equality (===) comparision. ( <a href="https://github.com/reduxjs/react-redux/blob/master/src/hooks/useSelector.js#L98">Click here if you are feeling like looking at the official repo&#39;s source code</a>). In the source code, useSelector by default uses a function called refEquality, and all it does is simply <a href="https://github.com/reduxjs/react-redux/blob/master/src/hooks/useSelector.js#L7">const refEquality = (a, b) =&gt; a === b</a>.</p><p>This means that if you are returning an object from useSelector for whatever reason, useSelector will cause a re-render every time an action is dispatched from the store, simply because objects of the same structure (same keys and values) do not strictly equal each other in javascript. For example, { a: 1 } === { a: 1 } is false. Official doc says the same:</p><blockquote><em>returning a new object every time will always </em><strong><em>force a re-render</em></strong><em> by default.</em></blockquote><p>Do they really force it? Yes. <a href="https://github.com/reduxjs/react-redux/blob/master/src/hooks/useSelector.js#L73">From the source code</a>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7173f58923373f844ed5375f0c5b1fd5/href">https://medium.com/media/7173f58923373f844ed5375f0c5b1fd5/href</a></iframe><p>So… now, with this in our mind, let’s go back to the options we saw previously.</p><h3>Option 1</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/872f303f50a04d3cf2cca56d1d486d74/href">https://medium.com/media/872f303f50a04d3cf2cca56d1d486d74/href</a></iframe><p><em>Catches:</em></p><ol><li>You are just writing a pair of shouldShowRed and shouldShowGreen for three times just to take the desired state out.</li><li>This will cause a re-render forcefully every time an action is dispatched, because you are returning a new object from your selector.</li></ol><p><em>Verdict</em>: not good enough.</p><h3>Option 2</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/caf26cf8ae142f53793179958e9bfda6/href">https://medium.com/media/caf26cf8ae142f53793179958e9bfda6/href</a></iframe><p><em>Catches</em>: you are returning the entire state from your selector, and destructuring it outside of the selector. This will too cause a re-render. What’s the point of having the selector callback if you intend to receive the entire state? This is a bad practice. It’s just tantamount to passing the entire state in mapStateToProps. You don&#39;t do that there. So, why here?</p><p><em>Verdict</em>: not good enough.</p><h3>Option 3</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c92fbe1768ce16a030d1f1cef4f7e3a7/href">https://medium.com/media/c92fbe1768ce16a030d1f1cef4f7e3a7/href</a></iframe><p><em>Catches:</em></p><ol><li>you are calling useSelector twice, and this does not matter. According to the official doc:</li></ol><blockquote><em>Because of the React update batching behavior used in React Redux v7, a dispatched action that causes multiple useSelector()s in the same component to return new values </em><strong><em>should only result in a single re-render.</em></strong></blockquote><p>2. strict equality is functioning as properly for each selected state because you are returning a primitive from each selector.</p><p><em>Verdict</em>: usable.</p><h3>Option 4</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c0d4d962f5ad8015cb5d795db3f6423b/href">https://medium.com/media/c0d4d962f5ad8015cb5d795db3f6423b/href</a></iframe><p><em>Catches</em>: It’s just the same as option 1 or 2. It will cause a re-render too.</p><p><em>Verdict</em>: Not good enough.</p><h3>Improving the bad options</h3><p>Thankfully, redux gives us a chance to insert our own equality functions. The concept is the same shouldComponentUpdate or the equality callback in React.memo. We could do this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/335c8fd714143d9ae0434d5acb7259b5/href">https://medium.com/media/335c8fd714143d9ae0434d5acb7259b5/href</a></iframe><p>or,</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/573f1a16f3b153981232d6e3a80114ea/href">https://medium.com/media/573f1a16f3b153981232d6e3a80114ea/href</a></iframe><p>Something like that. However you should really note that using deepEqual cannot ever be fast if you are trying to equal a large object (<a href="https://twitter.com/dan_abramov/status/1104414272753487872?s=20">Dan Abramov said it, too!</a>):</p><h3></h3><p>Deep equality checks are generally a bad idea. If the inputs are shallow enough that you think deep equality would still be fast, consider just using [JSON.stringify(obj)] instead. Note it won&#39;t compare functions.</p><h3></h3><p>Also &quot;fast-deep-equal&quot; is such a misleading library name. If it&#39;s deep it can&#39;t claim to be &quot;fast&quot; because you&#39;re at the mercy of your data structure. Some seemingly innocent changes to it can make the comparison super slow.</p><p>Note also that you only want to run deepEqual on what you need. In the code snippet above, you are also comparing shouldShowBlue which is a part of RootReduxState[&#39;conditions&#39;]. But you don&#39;t need that anyways, but you are still comparing it. Make sure you <em>select</em> and <em>compare</em> what you only need.</p><h3>But why would you try to optimize it in the first place?</h3><p>Well, at first, it’s totally okay. Your app has ~100 components only, your redux state is quite shallow, and it does not take a long time to render whatever’s being rendered.</p><p>The problem comes at two points:</p><ol><li><em>once you start to scale your application.</em> If you succeed in making a popular application, you are going to support more features, and thus, need more components. Your components will be numerous, leading to the point where re-render of expensive components will be causing a sluggish interaction.</li><li><em>once you start to care about users using low-end devices.</em> You want to support users with low-end spec computers. You want to support mobile devices with inherently less performance than most computers. Just get a 6x slowdown on your CPU from Chrome’s performance tool and try to see how long it takes for your components to react.</li></ol><h3>Conclusion</h3><p>So far we looked at possible problems with using useSelector and how to solve them:</p><ol><li>If you are returning an object from your selector callback, it’s going to force re-render by default.</li><li>To prevent re-render, either let your selector return a primitive type, or use a custom equality function.</li></ol><p>That’s it. Thank you!</p><p><em>Originally published at </em><a href="https://9oelm.github.io/2020-09-13--How-to-make-useSelector-not-a-disaster/"><em>https://9oelm.github.io/2020-09-13--How-to-make-useSelector-not-a-disaster/</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6fdd1c558fd3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/how-to-make-useselector-not-a-disaster-6fdd1c558fd3">How to Make useSelector Not a Disaster</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Learn All Major Functionalities on Chrome’s Performance Tab and Practice It With a Simple React…]]></title>
            <link>https://medium.com/swlh/learn-major-functionalities-on-chromes-performance-tab-and-practice-it-with-a-simple-react-project-98e0306aa7?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/98e0306aa7</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[optimization]]></category>
            <category><![CDATA[chrome]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Tue, 04 Aug 2020 16:36:18 GMT</pubDate>
            <atom:updated>2020-08-05T23:49:25.826Z</atom:updated>
            <content:encoded><![CDATA[<h3>Learn All Major Functionalities on Chrome’s Performance Tab and Practice It With a Simple React Project</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tw84Odwmv_DDUzGvrigooQ.png" /></figure><h3>Yes, Chrome’s performance tab is overwhelming</h3><p>First time you look into all the charts, you have no idea what means what. What do those different colors even mean? It’s not self-explanatory at all. There needs to be a guidebook.</p><p>In this article,</p><ol><li>I will briefly walk you through all functionalities of Chrome’s performance tab, with majority of the usual curiosities resolved.</li><li>Using what we learned, we will find what made our React components so slow and think about how to improve them.</li></ol><h3>A very simple example with React</h3><p>I wrote some short components, &lt;Item /&gt; and &lt;LongList /&gt;, to make an example for our article.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d121aaf82632537dd0f303568cb35243/href">https://medium.com/media/d121aaf82632537dd0f303568cb35243/href</a></iframe><p>And it’s showing me this, which is full of 4500 rows of &lt;Item /&gt; s and a button to make all 4500 rows again:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*jq1EsGZ-gDNeFT2hOum_WA.gif" /></figure><p>The entire loading is quite slow if you slow down CPU on Chrome, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*kqGjzgkedC09f2T3VOhxjA.gif" /></figure><p>This means that on lower-end PCs, it’s likely that it’s going to be slow like that too. Let’s guess for a second. What’s making this so slow? Network requests? generateManyRandomThings because it&#39;s producing so many elements in an array? Save your guess for now. We are going to investigate this thorougly as we are reaching the end of this guide.</p><p>You are able to see <a href="https://github.com/9oelM/react-optimization">the entire source code on Github (Chrome Performance profiles included)</a> and <a href="https://chrome-react-optimization.netlify.app/">access the deployed website on netlify</a>. Feel free to open up performance devtools on Chrome and try on your own (the production deployment might behave differently, though)</p><h3>An overview of all major functionalities in a single slide</h3><p>So here’s what those colors and jargons mean. Check this image out. I wanted to have it in a single slide so that I could grasp everything at one go <a href="https://9oelm.github.io/static/932657e305e7bdd40be574d3f5248437/d0cbe/overview.png"><em>(the resolution of the image below is poor, please open here for a good resolution)</em></a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kyZX4wXnvdQL5XTT9SSENw.png" /></figure><h3>Breaking down the overwhelming parts</h3><p>I will explain each part that seems to be overwhelming or not self-explanatory, one by one.</p><h4>Reload button</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/46/1*iJtUYTbPvRIxjsOf5GgbBg.png" /></figure><p>Clicking on the reload button will reload the page and start profiling automatically, and profiling will stop 3 seconds after the load event. This is useful for performance monitoring for initial load.</p><h4>Disable javascript samples</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/542/1*qXve0qpRQK-Zec_hc4rB3A.png" /></figure><p>Disabled (checked):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yYP8eM2y3Ngum4jDuAua1w.png" /></figure><p>Enabled (unchecked):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fsdq2RQqX4X4cmoDt5i2uA.png" /></figure><p>Clicking on this option disables showing call stacks of Javascript functions in the recording of <strong>Main</strong> panel. This means you cannot see names of functions called during execution at all.</p><h4>Enable advanced paint instrumentation</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/818/1*N3wOBGQNbtyBmnVcaVtLvA.png" /></figure><p>After ticking this checkbox, record the performance again.</p><ol><li>Click on the frame from <strong>Frames</strong> section;</li><li>Click on <strong>Layers</strong> panel at the bottom. You are going to see the layers at the time of that frame and can inspect them.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/975/1*ckmLb4wc7zilpzSeFtyZDw.png" /></figure><ol><li>Click on any of paint events from <strong>Main</strong> section</li><li>Click on paint profiler at the bottom. Inspect instructions and time taken to paint.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/1*FBeDsAtbI7Bfthns7ssRXA.png" /></figure><h4>Timeline</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/629/1*4LYtLcnPdABBiJqQN50Fbg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/413/1*CGvsFuJSjwY24hGOwVw_9w.png" /></figure><p><strong>Summary</strong> panel at the bottom of your <strong>Performance</strong> tab will show colors, and they directly match to the middle <strong>CPU</strong> region. Each same color means the same thing in the <strong>Timeline</strong> and <strong>Summary</strong> panel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/68/1*za3n-_K4pam0QPN8x-8g5w.png" /></figure><p>If you look at the rightmost side of your timeline, you are going to see <strong>FPS</strong> (topmost), <strong>CPU</strong> (middle), and <strong>NET</strong> (bottommost).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/189/1*4NKnRF-pL7AMszMJ-RBl9A.png" /></figure><p>The little red section in the pink bar means that FPS dropped so siginificantly that it may have harmed UX.</p><p>You can observe from the above picture that the FPS graph (green part) shows a drastic decrease in that pink and red region.</p><p>The part with hatched fill pattern means that the work was done off-main-thread (I do not know why Chrome does not tell us this in any direct way, although it’s quite confusing for people who are new to performance monitoring).</p><h4>Timings</h4><p>React records time taken for mount and update on Chrome by using <a href="https://web.dev/user-timings/">User Timing API</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*azlKIHiwQyAHUBSDFbOaEw.png" /></figure><p>You can see mount and update timings for all components. If you click on the chart, the bottom panel on Performance tab will show you detailed information about that component and its neighbor components. We will talk about this later more.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1004/1*ksVEEzFq-c2HK28YCitR0g.png" /></figure><p>If you want to inspect how and what functions are used in a specific components, we will have to dig <strong>Main</strong> panel. Hold on a sec until then.</p><p>Chrome also records important events:</p><ul><li>DCL (DOMContentLoaded): HTML is fully loaded and DOM tree is constructed. Stylesheets, images, iframes, other external resources may not have been loaded.</li><li>L(Load): Basically, DCL + all external resources loaded.</li><li><a href="https://developer.mozilla.org/en-US/docs/Glossary/First_paint">FP (First paint)</a>: ‘the time between navigation and when the browser renders the first pixels to the screen, rendering anything that is visually different from what was on the screen prior to navigation’</li><li><a href="https://developer.mozilla.org/en-US/docs/Glossary/First_contentful_paint">FCP (First Contentful Paint)</a>: time when some contentful thing (text, image, canvas, or SVG) is painted for the first time). The very first time user can start consuming page content.</li><li><a href="https://developer.mozilla.org/en-US/docs/Glossary/first_meaningful_paint">FMP (First Meaningful Paint)</a>: the time it takes for a page’s primary content (biggest layout change, probably the main HTML structure, and web fonts) to appear on the screen.</li><li><a href="https://web.dev/lcp/">LCP (Largest Contentful Paint, not in the picture below)</a>: the render time of the largest image or text block visible within the viewport.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/353/1*5ca_VoaqLvy50F8-WXYRaA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/344/1*F1pyUapvstc4BL8lpHoeIQ.png" /></figure><h4>Experience</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/465/1*dnUwIMzaWPOlJTC_9F96kg.png" /></figure><p><a href="https://developers.google.com/web/updates/2020/05/devtools#cls">Very recently, Chrome introduced ‘Experience’ panel</a>. It reports layout shifts for now. A <strong>layout shift</strong> is an <strong>unexpected movement of page content</strong> that usually happens because resources are loaded asynchronously or DOM elements get dynamically added to the page above existing content, harming UX.</p><p>I tried this on medium.com and luckily, I got one Layout shift:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/797/1*P5HHry06wW14-sirUTDH5w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/879/1*JgRxifFmUgs3UxRuLefOzA.png" /></figure><p>Notice that you could click on some little text buttons on the right-bottom side at about the beginning of 1600ms. But as you reach the beginning of 1800ms, these texts suddenly go away (probably to the bottom).</p><p>Chrome defines this behaviour as a source of harmful UX, especially when it comprises some crucial activities like payments or credentials.</p><p>You can inspect more information from the panel at the bottom:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/755/1*9RKpicizoJ8mec9xHCbxIQ.png" /></figure><h4>Main</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/847/1*uMCtqtlModzON9j-BulkUg.png" /></figure><p>So this is the interactive view of call stacks. The functions at the top are the ones that were called earlier; the ones at bottom called later. You can click around and inspect using any of <strong>Summary</strong>, <strong>Bottom-Up</strong>, <strong>Call Tree</strong>, and <strong>Event Log</strong> tabs from the bottom. These are the most important parts I wanted to know:</p><ul><li>Colors: they don’t have special meaning, but charts are colored in the way that would be easy for you to see pattern of execution.</li><li>Long tasks: the API reports any tasks that execute for longer than 50 milliseconds (ms). <a href="https://web.dev/long-tasks-devtools/#what-are-long-tasks">Keeping every task under 50ms ensures visible, immediate response for user once some interactive action was taken by user</a>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/672/1*AzZKO0H4maNEB5uWOdWhGQ.png" /></figure><p>If you look closely enough, you will find that Chrome already colors the duration of time that should be reduced to make a long task into a ‘bearable’ task, with red-gray hatch pattern.</p><ul><li>Navigation (pro tip): move around with WASD, and arrow up and down key for your ease. It’s unlikely you will use a mouse to navigate around <strong>Main</strong> once you get comfortable with this.</li></ul><h4>Raster and compositor</h4><p><strong>Rasterizing</strong> is converting visual information into pixels on the screen. Uses multiple threads (which are not part of the main thread).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/311/1*VPyPTSif-HTncTwVizM6tA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/370/1*sxGAa89bn6vtVMhk_qGAmw.png" /></figure><p><strong>Compositing</strong> is a separating parts of a page into layers (happens in a thread that’s different from rasterizing thread), and rasterize them separately (also happens in other threads).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/757/1*t1UQWEQhLacmV80TczpF3w.png" /></figure><p>We will cover these two in a different article because these make such a long topic themselves. For now, let us just be aware that there are these two things.</p><h3>Summary, Bottom-Up, Call Tree, and Event Log</h3><h4>Summary</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/397/1*PRAA0bHh4AbO2Hd5wbZrPA.png" /></figure><p>The <strong>range</strong> represents the duration selected in the timeline.</p><p>The legend on the right side shows:</p><ul><li>Loading: time taken for loading resources</li><li>Scripting: time taken to parse and evaluate javascript</li><li>Rendering(Layout): time taken to computing styles and positions of elements on the page. Not sure why Chrome names it <strong>Layout</strong> in the <strong>Main</strong> panel and <strong>Rendering</strong> here.</li><li>Painting: time taken to fill in the pixels</li><li>System: effectively, can be also called as others. All activities not belonging to the categories Loading, Scripting, Rendering, Painting and GPU.</li></ul><h4>Bottom-Up</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9RBuXzbx_sEG31GNhkiqxw.png" /></figure><ul><li><strong>Self Time</strong>: the time taken to execute code in the function itself, excluding the time to execute other functions it calls. (in the example, useState and moutState have almost 0% self time because the long lines of the chart are suddenly ending at generateManyRandomStrings which is causing all the heavy works.</li><li><strong>Total Time</strong>: the time taken to run functions (up to the end) from the current function.</li><li>Look for high total time branches, and then find the blocks with high self time. That’s the one that might be causing some performance problems.</li><li>In the example above, generateManyRandomThings accounts for 1.3% of rendering time of LongList, cumulatively. But its total time is 22.5%. So it should be that the functions it&#39;s running are doing costly works (the actual works done purely inside that function only aren&#39;t really slow).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/464/1*68gv6zWgEFKrDIv4CabAMg.png" /></figure><ul><li>Don’t be confused: if you open consecutive dropdowns under the first tab, you are tracing back to the initial function that was called. You are going down in the call stack. You are NOT going up.</li></ul><h4>Call Tree</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/493/1*I1IVJDz5D7EzmH5-0pqmLQ.png" /></figure><ul><li>It traces back to the root activity(or activities) that caused the function to be called.</li><li>In the example above, the root activity of initBackend is Function Call.</li></ul><h4>Event log</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/1*R5GZbfIUV51nwDUhfTXqyw.png" /></figure><ul><li>It shows chronological order of events.</li><li>In the example above, LongList was first called at 256.7ms, and then useState at 290.0ms, and then generateManyRandomThings at 290.2ms.</li></ul><h3>So how do I use this with React?</h3><p>Good question! Let’s now go back to our code. Then, let us slow down our CPU again. I’ve set it as 4x slowdown. Now, let’s try to feel the first loading speed (click on ‘Start profiling and reload page’ button). <a href="https://github.com/9oelM/react-optimization">For your information, you can download the performance profiles I’m using in this example from github</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*kqGjzgkedC09f2T3VOhxjA.gif" /></figure><p>Well, for sure, it took some time until you could first see anything from the browser. Now let’s look at the record:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o7KElNjya2J7AZ_b7ek5DA.png" /></figure><p>First let’s find from when the browser was fully ready before it started doing something with React.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aHlbMs27bGN18tzU8iNa7g.png" /></figure><p>We can see from above that the browser spent the first 500ms destroying the previous webpage (which was actually the same localhost:3000), requesting over network, parsing, and compiling resources like javascript and html files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/895/1*NjbU6c51TWqe7Nck4_qP9A.png" /></figure><p>Right after 500ms, we see that actual functions from React library itself as well as our ./src/index.js are being called. Let&#39;s look at it with Timings tab:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FPc3gPNzLSlHVBu4yZ186g.png" /></figure><p>The red rectangle is the execution of LongList (components are functions too!), and the blue rectangle is the execution of many Item s.</p><p>My personal, naive guess (without knowing anything well about how React should work in this situation) on why the FCP was so late before looking into the performance log was that generateManyRandomThings is running very slowly, simply because I thought it&#39;s putting so many elements into an array after numerous calculations.</p><p>But after inspecting the log, we find that the culprit is not generateManyRandomThings (under LongList):</p><p>1. Even just by looking at the chart, it’s evident that generateManyRandomThings is just a small part of the entire render process of &lt;LongList /&gt;. generateManyRandomThings was called twice because useState was repeatedly called twice during render; but both were still short. Below is the duration of the first execution of generateManyRandomThings. As you can see, it&#39;s really just a small part (red circle) under render:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/925/1*3HBSd4zHXiP46ac0Z1ivRg.png" /></figure><p>2. render took almost 2 secs total time, while generateManyRandomThings took only 54.1ms total time (2.7% of render&#39;s total time):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/1*Zz7dM9JiINHPAHyebiLbdw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/679/1*9-IKSvoIc8MoItmcEBpj7g.png" /></figure><p>Then what’s the main cause of slowness? Well, it turns out the culprit is &lt;Item /&gt;, as you might have easily spotted already.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/887/1*5bp_tnVELXga_tqZm8JWcw.png" /></figure><p>There are so many repeated processes going on for each of 4500 different &lt;Item /&gt;s. How can we optimize this then? In reality, we are perhaps going to use something like a virtual list, so that you only render what&#39;s inside your current viewport only. That&#39;s going to reduce a lot. Because making a virtual list is not the main topic here, let&#39;s just pretend we made it by reducing items down to 100 items, and see how our React app does again. For the sake of proof of performance, let&#39;s still make 4500 elements in the array and only render 100 &lt;Item /&gt; s, like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/474dfdb1607483d3304c1b4adc965cfb/href">https://medium.com/media/474dfdb1607483d3304c1b4adc965cfb/href</a></iframe><p>And the result…? Without even inspecting deeply, we can already feel that the initial load (the instant when the rows changed) time was greatly improved.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*3JHddGdk2uYAxK3JyzQaFw.gif" /></figure><p>ah, now we can see that the self-time of LongList finally became somewhat similar to total of execution of all Item s:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/830/1*N6ReIcl6qmJxqaAqXKSNaw.png" /></figure><p>Although it might sound very simple that mounting 4500 components is slower than putting strings and numbers into an array, it’s always worth trying out auditing performance using Chrome’s Performance tab, because until you inspect the real performance with logs and stats, you are essentially just guessing which part is supposed to be the slowest. In complex React apps, there’s only a low chance it’s going to work well that way.</p><h4>Last curiosity</h4><p>But why is useState being called twice anyways in a single mount, like this?:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/908/1*5eDYNW-ktvuJFG5iGpZgNw.png" /></figure><p>Well, it was not related to something we did! <a href="https://github.com/facebook/react/issues/15074">Dan Abramov says it always happens when you use </a><a href="https://github.com/facebook/react/issues/15074">&lt;React.StrictMode&gt;</a>. So there&#39;s nothing wrong with it. If we change</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cf4d8373cb1ac6528155ff038e916d66/href">https://medium.com/media/cf4d8373cb1ac6528155ff038e916d66/href</a></iframe><p>to</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a6a5208c32af8adff85eaf2908afbfa/href">https://medium.com/media/2a6a5208c32af8adff85eaf2908afbfa/href</a></iframe><p>It’s going to show you only a single execution of useState, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/1*9PXKWnsRXJ8WurjmxpeWbA.png" /></figure><h3>Closing notes</h3><p>So.. that’s it! We covered most basic concepts. In near future, I will also cover GPU, Interactions, and some few parts I saved for another chance. We will also look into how to optimize complex React + Redux applications with Chrome’s Performance panel later.</p><p>Thank you for reading!</p><p><em>Originally published at </em><a href="https://9oelm.github.io/2020-08-03--Learn-all-major%20functionalities-on-Chromes-Performance-tab-and-practice-it-with-a-simple-React-project/"><em>https://9oelm.github.io/2020-08-03--Learn-all-major%20functionalities-on-Chromes-Performance-tab-and-practice-it-with-a-simple-React-project/</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=98e0306aa7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/learn-major-functionalities-on-chromes-performance-tab-and-practice-it-with-a-simple-react-project-98e0306aa7">Learn All Major Functionalities on Chrome’s Performance Tab and Practice It With a Simple React…</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Extensive introduction to why and how you might want to use and test redux-observable]]></title>
            <link>https://levelup.gitconnected.com/extensive-introduction-to-why-and-how-you-might-want-to-use-and-test-redux-observable-1f2987407166?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/1f2987407166</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[redux]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[reactive-programming]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Mon, 27 Jan 2020 10:15:42 GMT</pubDate>
            <atom:updated>2020-02-01T07:53:51.485Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iYI_gEiH-hbCXA6z0kkQHQ.jpeg" /><figcaption>Just a random image like everyone else does (credit: <a href="https://unsplash.com/@genessapana">Genessa Panainte</a> from unsplash)</figcaption></figure><p>I was struggling at my company trying to write some tests for redux-observable operations. Most of the network requests were managed by RxJS, and none of them were covered by tests. I wanted to write tests but just did not know how to.</p><p>But I really just wanted to start from the basics — I mean, the very basics, including why, and how we might want to use redux-observable.</p><h3>tl;dr</h3><p>If you want to hop straight into the source code, <a href="https://github.com/9oelM/redux-observable">here it is.</a></p><h3>What is reactive programming?</h3><p><a href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#reactive-programming-is-programming-with-asynchronous-data-streams">Reactive programming</a> is programming with asynchronous data streams.</p><ul><li>Typical events are async event streams and you want to observe over them</li><li>You have useful functions to combine/create/filter those streams</li></ul><p>A <strong>stream</strong> is a sequence of ongoing events ordered in time. It can emit three different things: a value (of some type), an error, or a “completed” signal.</p><p>We capture these emitted events only asynchronously, by <strong>defining a function that will execute when a value is emitted,</strong> another function when an error is emitted, and another function when ‘completed’ is emitted.</p><p>So this is essentially going back to <a href="https://github.com/9oelM/frontend-interview#observer">the observer design pattern</a>.</p><h3>Why bother to use RxJS?</h3><h4>Abstraction</h4><p>If you use RP, you don’t have to really worry about implementation details, because it gives you a high level abstraction layer. So you never have to bother with Promises and await in javascript anymore. Just declaratively implement what you want to do, and that&#39;s it.</p><h4>Async works made easier</h4><p>Nowadays async operations have become a common thing because you might need to handle UI interactions &amp; tonnes of network requests.</p><p>So there’s a good chance that it is going to be a good fit for heavily network based application (both for frontend and backend).</p><h4>Lots of helper functions to simplify work declaratively</h4><p>You have dedicated helper functions to implement what you want to do, which otherwise you might do in a very complex way. Even if this does not fully come to your mind right now, you are going to notice it as you go through this article.</p><h3>Why bother to use it with Redux?</h3><p>Now we have a brief understanding of advantages of using RxJS. Now, we want to handle actions in Redux, but not all actions are synchronous.</p><p>For a simple example, I have written an application that fetches text from the server and shows it, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*Qh_A8y_VSV7iUuiUbIhEtg.gif" /></figure><blockquote><em>I assumed that you have a prior knowledge of some Typescript and React fundamentals including hooks.</em></blockquote><p>This is the project structure (omitted unimportant ones):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1aa4adf710bffd7fe48f3cdfc1968229/href">https://medium.com/media/1aa4adf710bffd7fe48f3cdfc1968229/href</a></iframe><h4>Redux-related things first</h4><p>To be able to understand true benefits of using redux-observable, we need to see how redux works first, so that we can compare (you can skip this part if you already have an idea of how you would handle async actions with bare redux)</p><p>In redux, as you know, we mainly have actions and reducers. I have created three types of actions:</p><ol><li>StartRequestText: I will dispatch this right before fetching from the dummy text API.</li><li>FinishRequestText: I will dispatch this right after receiving the text.</li><li>ErrorRequestText: I will dispatch this as soon as I encounter an error in the process described above.</li></ol><p>The above actions are implemented like this in actions.ts:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4104aac392769c8460aae8331b8f9080/href">https://medium.com/media/4104aac392769c8460aae8331b8f9080/href</a></iframe><p>And I simply defined some action types in constants.ts:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/de379c6e2b1eac492baa8d78e727de23/href">https://medium.com/media/de379c6e2b1eac492baa8d78e727de23/href</a></iframe><p>Putting them into reducer.ts is not difficult at all. We just have to update the state for each different action. You can see that I&#39;m updating isLoading, text, and errorMsg individually according to each type of an action:</p><p>reducer.ts</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/39be641dc2b7d718d9b778b9feeb0674/href">https://medium.com/media/39be641dc2b7d718d9b778b9feeb0674/href</a></iframe><p>Again, not so much in store.ts. Just combine reducers (although we just have one, which is not usual in production envrionments) and configure redux devtools extension, and create store.</p><p>store.ts</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/21df205bedf944bcf0b75b289291af18/href">https://medium.com/media/21df205bedf944bcf0b75b289291af18/href</a></iframe><p>And I defined the types we need in types.ts:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3f5a2ccb50d373a9a1f7524f9d4b9633/href">https://medium.com/media/3f5a2ccb50d373a9a1f7524f9d4b9633/href</a></iframe><p>App.tsx In the parent component, we just want to show two things: the button and the text.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/60033856fdf69cb3541b176c0a06f7b0/href">https://medium.com/media/60033856fdf69cb3541b176c0a06f7b0/href</a></iframe><p>DummyTextRequestButton.tsx</p><p>In this component, we have the logic of dispatching all of the actions we have defined earlier. You have to recognize that we want to port the logic in handleClick to redux-observable later, because right now it&#39;s not reactive at all.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac18e5cfb52598c12fdcc1ab2292d8c5/href">https://medium.com/media/ac18e5cfb52598c12fdcc1ab2292d8c5/href</a></iframe><p>DummyTextViewer.tsx</p><p>This component consumes the redux state. Shows error, text, or loading based on the state.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/df534928e672d8cbbc8a4924666c682d/href">https://medium.com/media/df534928e672d8cbbc8a4924666c682d/href</a></iframe><h3>With RxJS and redux-observable?</h3><p>First of all, we are going to introduce relevant modules to our project:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/92446b5d838250126249aa72bfbb23b0/href">https://medium.com/media/92446b5d838250126249aa72bfbb23b0/href</a></iframe><p>Then we want to get rid of somewhat complex logic inside DummyTextRequestButton.tsx:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/83d5c02cdc45c6a761f9af3b2188f783/href">https://medium.com/media/83d5c02cdc45c6a761f9af3b2188f783/href</a></iframe><p>We can do it like above because we are going to port our logic to redux-observable.</p><p>Then, we are going to create something called epics.ts inside redux folder:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/606aa2d9a231c6240c27a5755f573d5e/href">https://medium.com/media/606aa2d9a231c6240c27a5755f573d5e/href</a></iframe><blockquote><em>An </em><strong><em>epic</em></strong><em> is really just something that listens to a redux action and outputs other actions accordingly.</em></blockquote><p>So how is that done in the code above? We can see that startRequestTextEpic is listening to an action of the type called C.START_REQUEST_TEXT only. So this code, won&#39;t get executed it any other actions are dispatched from redux.</p><p>Ok, forget about mergeMap for now and then let&#39;s go on for now. We can see that we are using RxJS&#39;s own fetch method called fromFetch, which essentially just makes fetch into an observable.</p><p>Now you process the response from fetch, and the text inside the response would be a payload to finishRequestText action.</p><p>Otherwise, if you have an error while fetching, the error is going to be caught and will dispatch errorRequestText action.</p><p>In this way, we have successfully ported our implementation in handleClick to inside an epic, and all that&#39;s left for we us to do is actually configure a few things in store.ts to be able to use redux-observable in our project:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/52225a888c2712db2d9292486b0ce9a5/href">https://medium.com/media/52225a888c2712db2d9292486b0ce9a5/href</a></iframe><p>So, after adding redux-observable, now we have some benefits:</p><ol><li>Reactiveness. You can easily handle asynchronous actions and state updates in redux by reacting to actions being dispatched.</li><li>Separation of concerns. Now you don’t have to care about what to do after startRequestText in DummyTextButton, because all of the logics have been ported to startRequestTextEpic.</li><li>Great toolchains. Right now we have used just few functions from RxJS, but combination of many functions will make it easier to process your data streams.</li></ol><h3>Extending further by utilizing what RxJS has</h3><p>Now we have one little problem: when a user clicks on the button many times in such a short time, the request is going to be sent more than one time, which might be kind of useless, as shown in this gif:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*8jN3kpzDFSalsJ2-igqEFA.gif" /></figure><p>I clicked on the button three times, but actually what you all need is just a single request. So here’s what you can do:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d678aba9eae3dacd31bd40cce00044e1/href">https://medium.com/media/d678aba9eae3dacd31bd40cce00044e1/href</a></iframe><p>We just added debounce, and it is going to filter out only one action of type START_REQUEST_TEXT for a second, which means even if you click on the button three times in a single second, the request is going to be sent only once, like in the gif below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*vJIKHyD8eD4md9T9wxN0Ig.gif" /></figure><p>Alternatively, what you would want better is actually switchMap; It would cancel any pending request and switch to the last one:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b42f0a192e1033d9f41ab4ca72a9c4e1/href">https://medium.com/media/b42f0a192e1033d9f41ab4ca72a9c4e1/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*GGEdTm_0eA4NBD18Dd43Hg.gif" /></figure><p>Now, let’s say that you would have another button to show some other text, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*7EPpMVogNObk75_SeEFU5Q.gif" /></figure><p>Because we now have an additional UI, we need to handle one special case (we are not going to cover other cases, although there are many): <strong>you click on request dummy text button, but you change your mind to see hi instead</strong>. Then you would need to <strong>cancel and finish</strong> your action.</p><p>For the sake of simplicity, I’m not going to show the entire code but epics.ts to demontrate that (you can still look into <a href="https://github.com/9oelM/redux-observable/tree/master/redux-observable">the entire codebase from the Github repository</a>):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8106821cec142dfbc33c738a0851e26e/href">https://medium.com/media/8106821cec142dfbc33c738a0851e26e/href</a></iframe><p>We now have two major parts: sendRequest$ and cancelRequest$. In cancelRequest$ ovservable, we are going to force finish requesting text, because there is no need to request the text anymore if you have switched to see the hi text.</p><p>race would take the job of cancelling out any other ongoing action if the other action is finished. It&#39;s just like Promise.race in javascript! So, let&#39;s see this in gif:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*-W6L7V0X0VHTc7X86z_kcQ.gif" /></figure><h4>Checkpoint</h4><p>Do you now get why you would use redux-observable? It equips you with a nice set of tools to perform side-effects after actions are dispatched in redux. Otherwise it should have been a great pain for you manage events like cancellation manually, in vanilla javascript.</p><p>But hey, we are not done yet. Let’s finish it with a guide to how to test these epics.</p><h3>Testing your epics</h3><h4>Method 1: Test output actions based on input actions.</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6ab54b1865b4b8c060138bbd28cf9d68/href">https://medium.com/media/6ab54b1865b4b8c060138bbd28cf9d68/href</a></iframe><p>Whoa, lots of things to go through, right? But basically, all we are doing are just:</p><ol><li><strong>Mocking functions from certain modules to make them work according to our purpose</strong>. We are mocking rxjs.race and FF.fromFetch because, for race, we don&#39;t want race won&#39;t work well in a test environment and we can decide on which observable to emit, instead of depending on the code itself, and for fromFetch, we don&#39;t want to use real fetch because it is going to take more time for no useful reason.</li><li><strong>Running the epic with initial action and state</strong>. The epic will run, and spit out another set of actions as a result.</li><li><strong>Testing the equality of the output actions with the expected</strong>. We just need to test if the epic gives expected set of actions.</li></ol><p>That’s pretty much it! But we need to test more, so why not simplify this process with a simple function?:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7c75867b9a021509ce4448b33ad77796/href">https://medium.com/media/7c75867b9a021509ce4448b33ad77796/href</a></iframe><p>Now, we can turn out test into:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/647b240783ed10b475d7222831307527/href">https://medium.com/media/647b240783ed10b475d7222831307527/href</a></iframe><p>Much less boilerplate, right?</p><p>Now we can write out tests for other things as well, like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/53700e03bc5dc4eb2e8bb2d09c113806/href">https://medium.com/media/53700e03bc5dc4eb2e8bb2d09c113806/href</a></iframe><p>Now you’ve got to see all of your tests pass:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QZMqpDe30Ngd0AdwPmqH9g.png" /></figure><h4>Method 2: Use marble tests</h4><p>Previously, we’ve only used some basic methods to test epics. Using marble tests would allow you to focus more on <em>when</em> and <em>what </em>things happen.</p><p>If you are not familiar with the marble diagrams, please refer to <a href="http://reactivex.io/documentation/observable.html">ReactiveX’s explanation on marble diagrams</a>. Alternatively, there are many other good resources out on the web.</p><p>For the marble syntax, refer to <a href="https://rxjs-dev.firebaseapp.com/guide/testing/marble-testing#marble-syntax">rxjs API docs</a>.</p><h4>Hot vs Cold observables</h4><p>There was a great article on Medium that simplified the definition of hot and cold observables, <a href="https://medium.com/@bencabanes/marble-testing-observable-introduction-1f5ad39231c#f123">so I excerpted the definitions from it</a>. (Or look at <a href="https://rxjs-dev.firebaseapp.com/guide/testing/marble-testing">rxjs API doc</a>)</p><p>cold: begins subscription when the test begins.</p><blockquote><em>cold(--a--b--|, { a: &#39;Hello&#39;, b: &#39;World&#39; }) → Emit &#39;Hello&#39; at 30ms and &#39;World&#39; at 60ms, complete at 90ms.</em></blockquote><p>hot: begins subscription at the point of caret.</p><blockquote><em>hot(--^--a--b--|, { a: &#39;Hello&#39;, b: &#39;World&#39; }) → Subscription begins at point of caret, then emit &#39;Hello&#39; at 30ms and &#39;World&#39; at 60ms, complete at 90ms.</em></blockquote><h4>Testing events in relation to time</h4><p>What we couldn’t really answer using method 1 was something like ‘can actions be really be cancelled if there are multiple action inputs, because we are using switchMap?&#39;</p><p>Now because we have a control over time, this is totally possible.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8da1b494bab6f0fbfc8cb3f23ae1d57b/href">https://medium.com/media/8da1b494bab6f0fbfc8cb3f23ae1d57b/href</a></iframe><p>This one is really basic; We request text, and for the sake of the test, we delay the response from fromFetch by 1ms. Then we run START_REQUEST_TEXT, and expect the output action to be FINISH_REQUEST_TEXT after another 1 ms elapses. Simple. Right?</p><p>But what about some more complex test, like actions being cancelled because of switchMap?:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f15557e880f4b7ca0bc3822fdd755c01/href">https://medium.com/media/f15557e880f4b7ca0bc3822fdd755c01/href</a></iframe><p>In the above code, we are faking fromFetch again, and this time it is going to get you a response after 5ms. Now you decide to START_REQUEST_TEXT four times just in 4ms, in a row, each for each 1ms.</p><p>Then what is supposed to happen is that all of a, b, c get cancelled, because they are cancelled by the actions dispatched right after them, at the time fromFetch has not returned a response yet. This is what switchMap exactly does. It will cancel other observables and only emit the most decently projected observable, which is d (after 5ms).</p><p>So that’s basically it! Of course, we could again make an abstraction of this testing logic, just like we did for runEpicTest, but too bad - I&#39;m too tired right now, so I will leave that work left for you. :)</p><h3>Conclusion</h3><p>So far, we’ve covered:</p><ol><li>why you might want to use rxjs and redux-observable (maybe you could suggest more reasons in the comments section)</li><li>how you could replace redux based code into a redux-observable one</li><li>extensibility (benefits) of using redux-observable, especially for a complex logic</li><li>two methods of how you can test your epics</li></ol><h3>Appendix</h3><p>Just some last words for you.</p><h4>Suspicion on ‘always a pass’</h4><p>Sometimes, it’s hard to know if your test is really working or just being passed because jest finishes tests earlier than the time you want. <a href="https://jestjs.io/docs/en/asynchronous">Make sure you use </a><a href="https://jestjs.io/docs/en/asynchronous">done</a>, and if you are still not sure, try to break the test by changing something like expect(...).toEqual(...) to expect(...).not.toEqual(...). Then you should see something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yDyC3hzV-6wP9myFegLi7w.png" /></figure><p>if your tests are still being passed, then there’s a problem.</p><h4>Shoudn’t I test how epic changes the state as well?</h4><p>No. Because you are supposed to test an epic on <em>how set of actions outputs another set of actions.</em></p><p>You are going to test that in your tests for reducer, because reducer is actually where the action will change the state.</p><p>What epic really does is just until dispatching actions. Of course, it’s related to the state because it uses it, but it does not directly modify the state. That’s going to be left for the role of the reducer.</p><h4>Source code repository</h4><ul><li><a href="https://github.com/9oelM/redux-observable/tree/master/redux-only">redux implementation</a></li><li><a href="https://github.com/9oelM/redux-observable/tree/master/redux-observable">redux-observable implementation and tests</a></li></ul><p>And… thank you for reading!</p><p><em>Originally published at </em><a href="https://9oelm.github.io/2020-01-24--Fundamental-yet-extensive-introduction-to-why-and-how-you-might-want-to-use-redux-observable-for-async-actions/"><em>https://9oelm.github.io/2020-01-24--Fundamental-yet-extensive-introduction-to-why-and-how-you-might-want-to-use-redux-observable-for-async-actions/</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1f2987407166" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/extensive-introduction-to-why-and-how-you-might-want-to-use-and-test-redux-observable-1f2987407166">Extensive introduction to why and how you might want to use and test redux-observable</a> was originally published in <a href="https://levelup.gitconnected.com">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[…].forEach(saveFromZombies) does not always save people]]></title>
            <link>https://javascript.plainenglish.io/foreach-savefromzombies-does-not-always-save-people-217108c6921d?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/217108c6921d</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Sat, 12 Oct 2019 11:35:01 GMT</pubDate>
            <atom:updated>2019-10-13T09:37:24.432Z</atom:updated>
            <content:encoded><![CDATA[<h4>Oddities with how forEach works in JavaScript</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1b132gl04Zqs2HV3Ko7OEg.png" /><figcaption>Walking dead!!</figcaption></figure><h4>The first encounter with the problem.</h4><p>I was coding as usual. And I faced an odd encounter with how forEach works. Here goes the code to give an example of that. Imagine the code below is the code from one of the libraries I was using:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d3447a134facbaff3eca5bf46856725b/href">https://medium.com/media/d3447a134facbaff3eca5bf46856725b/href</a></iframe><p>And I spotted the code in my company’s app that was kind of doing:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4800a7ea966c735f554d592428709d5a/href">https://medium.com/media/4800a7ea966c735f554d592428709d5a/href</a></iframe><p>Of course, I did not want this. It’s against DRY principle. So I refactored the code to:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7e005a2d778ccf9c2c30a37a1e441931/href">https://medium.com/media/7e005a2d778ccf9c2c30a37a1e441931/href</a></iframe><p>Cooler and more succinct.</p><p>But I was very well tricked into thinking that this would just work. See what this code gave:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5c014a0728711c7c4efbe3466208d5dc/href">https://medium.com/media/5c014a0728711c7c4efbe3466208d5dc/href</a></iframe><p>Oops. Everybody’s dead. Ok. Now you are starting to get a grasp of why.</p><p>It’s the binding. Let’s check what this is actually doing inside our code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6c5dde2bbaf18f46b22795f9985407e0/href">https://medium.com/media/6c5dde2bbaf18f46b22795f9985407e0/href</a></iframe><p>Well, no surprise. It outputs:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b9de1bc8a0854e035e1b9910926c6169/href">https://medium.com/media/b9de1bc8a0854e035e1b9910926c6169/href</a></iframe><p>Ok. So here’s the main point of this article:</p><blockquote><strong><em>Just passing in the reference of a function that uses </em></strong><strong><em>this referring to somewhere else than a </em></strong><strong><em>globalThis, into a </em></strong><strong><em>forEach might cause an error in javascript because </em></strong><strong><em>this will point to a global </em></strong><strong><em>this.</em></strong></blockquote><p>So what do we do? Here are some things to let you know:</p><h3>1. Explicitly call the function</h3><p>Yeah this works. This will save some of the guys’ lives.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1106ff8c294b5f59759d8dcc06218050/href">https://medium.com/media/1106ff8c294b5f59759d8dcc06218050/href</a></iframe><p>Same for the normal function as well:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f246d7aef2a0b87ae06ec064b642ac19/href">https://medium.com/media/f246d7aef2a0b87ae06ec064b642ac19/href</a></iframe><h3>2. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Syntax">Pass </a><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Syntax">thisArg as an argument</a></h3><p>These are the parameters for forEach:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e8e88427f601b0a3bcacc258eee37dc0/href">https://medium.com/media/e8e88427f601b0a3bcacc258eee37dc0/href</a></iframe><p>You can put in the object to be pointed to as this inside saveFromZombies.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ad5e10b57f74fd00d6bf8923f0aafcbe/href">https://medium.com/media/ad5e10b57f74fd00d6bf8923f0aafcbe/href</a></iframe><h3>3. Use bind</h3><p>This is an explicit binding. You tell the javascript engine that you want saveFromZombies to be bound to walkingDead object.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/901b071031520ae5fe5592ba46ff554e/href">https://medium.com/media/901b071031520ae5fe5592ba46ff554e/href</a></iframe><h3>Further..</h3><p>Of course, we can, and should, apply the same principle when dealing with map, filter, ... and more.</p><h3>Summary</h3><ul><li>We have looked at how this might lose context when we put a reference of a function as a callback to forEach.</li><li>The solutions are: (1) Explicitly call the function, (2) Pass thisArg as an argument, and (3) Use bind.</li></ul><p>Happy forEach coding!</p><p><a href="https://9oelm.github.io/2019-10-12--[...].forEach(sayHello)-does-not-always-say-hello/"><em>Originally published at https://9oelm.github.io/2019-10-12--[...].forEach(sayHello)-does-not-always-say-hello/</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=217108c6921d" width="1" height="1" alt=""><hr><p><a href="https://javascript.plainenglish.io/foreach-savefromzombies-does-not-always-save-people-217108c6921d">[…].forEach(saveFromZombies) does not always save people</a> was originally published in <a href="https://javascript.plainenglish.io">JavaScript in Plain English</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making stupid React smart in re-rendering]]></title>
            <link>https://medium.com/swlh/making-stupid-react-smart-in-re-rendering-5f04b5bab327?source=rss-412dae67af0b------2</link>
            <guid isPermaLink="false">https://medium.com/p/5f04b5bab327</guid>
            <category><![CDATA[optimization]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Joel Mun]]></dc:creator>
            <pubDate>Thu, 03 Oct 2019 05:08:41 GMT</pubDate>
            <atom:updated>2020-03-17T14:23:23.208Z</atom:updated>
            <content:encoded><![CDATA[<h3>I believed React is smart enough to know this…. but aye?</h3><p>We had a bunch of large component trees in our company’s web application. And I saw them re-rendering from the top to deep down to the bottom for no reason. At first, I thought it would be easy to get them correct.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1012/0*o2hUC5r630BpH-b1.png" /></figure><p>Of course, the tree was much bigger than this. The tree didn’t just reach the end. This made useless re-rendering even a bigger concern. From the top to bottom, Provider, ConnectedRouter, App, PersistGate, ComponentA, ComponentB, .... and so on.</p><p>And I saw that there were no use of shouldComponentUpdate/ PureComponent/ memo in our app yet. So I decided to make use of them, still not yet aware of what was to come for me.</p><h3>Takeaway 1: Parent component pretty much does not care about its children</h3><p>I was optimizing the app and witnessed an interesting fact. Here’s the code to demonstrate it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b314f279c0a9bcee4323d470374f4063/href">https://medium.com/media/b314f279c0a9bcee4323d470374f4063/href</a></iframe><p>And do you think Child1 and Child2 are going to re-render upon Parent component&#39;s mouseEnter? See what happens:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JnN0GZnPYO-5S1AC.gif" /></figure><p>Oops. <strong>They re-render.</strong> But I do not see a reason why (The same thing happens for class components, if you wonder. You can try that!). The children do not even have their own props or states to listen for any changes. How can this happen? This is from React&#39;s own documentation:</p><blockquote><em>shouldComponentUpdate() is invoked before rendering when new props or state are being received. </em><strong>Defaults to true.</strong></blockquote><p>It defaults to true! What… Ok. React is made that way.</p><p>Then how can we make it better?</p><h3>Takeaway 2: use the children prop</h3><p>Ok. The only difference is that <strong>we use children prop</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1ced6affc51a155035a236e04e3aab21/href">https://medium.com/media/1ced6affc51a155035a236e04e3aab21/href</a></iframe><p>And the result?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dluvjBX3I_tV5N8T.gif" /></figure><p>It <strong>does not re-render the children components anymore</strong>! I still have not understood exactly why React <em>can</em> in this code but <em>cannot</em> in the previous code, but this is what it is.</p><h3>Takeaway 3: use React.memo</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4232d6a91ea939125f99e3c7e35e7db7/href">https://medium.com/media/4232d6a91ea939125f99e3c7e35e7db7/href</a></iframe><p>memo literally memoizes the functional component receiving a certain props, and if the props stay the same, it will just return the previously rendered (same) component. The result? Same as solution 1. It does not re-render Child1 and Child2. So I&#39;m just gonna copy and paste the gif from above for those who are lazy to read what&#39;s written, just like me:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*BsJejWfLuhKmzup4.gif" /></figure><p>Ok. But if you are using passing in nested objects as props, you should implement your own areEqual function for memo, like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/24326967a55fc2dca3929eb239fa83ea/href">https://medium.com/media/24326967a55fc2dca3929eb239fa83ea/href</a></iframe><p>Yeah. I know it’s an ol’ school style to check nested object equality, but it works well. In practice, <a href="https://github.com/FormidableLabs/react-fast-compare">you use something like </a><a href="https://github.com/FormidableLabs/react-fast-compare">isEqual from </a><a href="https://github.com/FormidableLabs/react-fast-compare">react-fast-compare</a> that would handle nested object comparison for you.</p><p>Ok. Now, what’s the result?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FTCN_0GniG0xybWD.gif" /></figure><p>Child1 no longer knows obj prop stays the same because memo only runs a shallow comparison between prevProps and nextProps But Child2 exactly knows, by using areEqual function, that obj is actually staying the same and therefore it does not need to re-render itself.</p><h3>Takeaway 4: Use PureComponent/shouldComponentUpdate</h3><p>Of course, you might wanna use your class component. So here’s a brief explanation on that as well:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9dfc652ad39c2e4fa593d6f7ddfda31d/href">https://medium.com/media/9dfc652ad39c2e4fa593d6f7ddfda31d/href</a></iframe><p>Above is an exact replica of the functional component implementations. Here are the details:</p><ol><li>You use PureComponent for Child1, but it won&#39;t serve its purpose, just like memo, because it has a nested object as its prop. It will keep re-rendering upon its parent component re-rendering. It would work if there were no nested object properties.</li><li>You use shouldComponentUpdate for Child2 and it will work. It compares nested objects just like areEqual. In case there is a state, you can use nextState to compare with this.state (previous state).</li><li>It’s just so annoying to write lots of boilerplate of codes for a class component. That&#39;s why I prefer functional components... (yeah I digressed a bit)</li></ol><p>Of course, the result is the same as the last code snippet. Let’s again copy and paste the same gif for the people:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*LYVBrbS80sXONQey.gif" /></figure><h3>Takeaway 5: Deal with functions from props when comparing</h3><p>There are many cases where props are functions, especially when you plug your functions into components with redux’s mapDispatchToProps, or passing your functions as props from parent down to children to get notified of what happened in children.</p><p>Dealing with functions might sound like really a basic thing, but it can really harm your application’s performance if you don’t do.</p><p>We see lots of patterns like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e7f4761ade5e3f54963ed11a52700680/href">https://medium.com/media/e7f4761ade5e3f54963ed11a52700680/href</a></iframe><p>Details:</p><ol><li>Now, the obj prop no longer an object. It&#39;s just become num.</li><li>You are passing a function called sayHiInChildren to Child2 as a prop.</li><li>You shallowly compare if all props are the same, both in Child1 and Child2, albeit using different ways (Child1 is not using a custom areEqual function, but Child2 is. But essentially they are doing the same thing in this context).</li><li>Everything is going to re-render although props to Child1 and Child2 are staying exactly the same. Look at the result:</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Yg5hKyDO78-8rD_I.gif" /></figure><p>But why!? Well..</p><p>In javascript, there is hardly a way to compare functions.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/00b7cf2cd345f4f07405ee31fb4c27f2/href">https://medium.com/media/00b7cf2cd345f4f07405ee31fb4c27f2/href</a></iframe><p>This will always return false, because functions are objects in javascript, meaning they are compared not with values, but references:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b60cfebc52d8029958c52d89d524f954/href">https://medium.com/media/b60cfebc52d8029958c52d89d524f954/href</a></iframe><p>The only way to make it possible is to have the same reference:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/937871ec6d10d4dc9d9385452c4d900f/href">https://medium.com/media/937871ec6d10d4dc9d9385452c4d900f/href</a></iframe><p>Then how can we deal with functions in props? Well, there are 4 ways:</p><ol><li>Exclude them</li><li>Stringify them</li><li>Use useCallback</li><li>Bind the function to the class</li></ol><h3>1. Exclude them (not recommended)</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/390f20b3a5cde9cbc5e6be349a1ec61c/href">https://medium.com/media/390f20b3a5cde9cbc5e6be349a1ec61c/href</a></iframe><p>You can use lodash’s _.isFunction to check if something is a function. Then you only have object properties that are not functions, to apply that to areEqual function.</p><p>Now, you can do this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4dc44e1070a805ad32347f3e013336b8/href">https://medium.com/media/4dc44e1070a805ad32347f3e013336b8/href</a></iframe><p>Result? Only parent component re-renders. Essentially, you are only comparing props which are not functions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cfRrU0YHBlSSscmO.gif" /></figure><h3>2. Stringify them (not recommended)</h3><p>By default, JSON.stringify does not support stringifying functions. So you&#39;ve gotta use third party libaries like <a href="https://github.com/vkiryukhin/jsonfn#readme">jsonfn</a>.</p><p>Let’s do this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/eb0ebf511f289cf6db72f1b21e56e1ce/href">https://medium.com/media/eb0ebf511f289cf6db72f1b21e56e1ce/href</a></iframe><p>JSONfn.stringify will generate a string looking like:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b9cfc8f18ae75f98503533f03998f17f/href">https://medium.com/media/b9cfc8f18ae75f98503533f03998f17f/href</a></iframe><p>Using this function will give you the same result as the last example. Here’s another copy and paste:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CliUqRDf-97VEZu0.gif" /></figure><h3>3. Use useCallback</h3><p>Probably this is the wisest solution when you are trying to prevent rerender in a functional component.</p><pre>const sayHiInChildren = useCallback(child =&gt; console.log(`hi~~~~~~~~~ — from ${child}`), [])</pre><p>useCallback will look at the dependencies fed into the array and will only give a different function when some dependency changed. Otherwise it is going to return a memoized callback, which won’t cause a rerender even if it’s fed as a prop.</p><h3>4. Bind the function to the class</h3><p>As you know useCallback cannot be used in class components.What can we do in the class components?</p><p>You can either do:</p><pre>class Parent extends React.Component {<br>  sayHiInChildren = child =&gt; console.log(`hi~~~~~~~~~ - from ${child}`);<br><br>  render() {<br>    return &lt;div onMouseEnter={handleMouseEnter} style = {{border: &#39;1px solid black&#39;, padding: &#39;50px&#39;}}&gt;<br>      Parent. Count: {count}<br>      &lt;Child1 num={1} sayHiInChildren={sayHiInChildren}/&gt;<br>      &lt;Child2 num={2} sayHiInChildren={sayHiInChildren}/&gt;<br>    &lt;/div&gt;<br>  }<br>}</pre><p>or</p><pre>class Parent extends React.Component {<br>  constructor(...args) {<br>    super(...args);<br>    this.sayHiInChildren = this.sayHiInChildren.bind(this);<br>  }<br><br>  sayHiInChildren(child){<br>    console.log(`hi~~~~~~~~~ - from ${child}`);<br>  }<br><br>  render() {<br>    return &lt;div onMouseEnter={handleMouseEnter} style = {{border: &#39;1px solid black&#39;, padding: &#39;50px&#39;}}&gt;<br>      Parent. Count: {count}<br>      &lt;Child1 num={1} sayHiInChildren={sayHiInChildren}/&gt;<br>      &lt;Child2 num={2} sayHiInChildren={sayHiInChildren}/&gt;<br>    &lt;/div&gt;<br>  }<br>}</pre><p>The two methods differ only in the syntax (arrow function binds directly to the parent context, while traditional function has to be bound manually), and they bring the same effect. In this way, you can retain a consistent reference of a function, which will allow you to prevent useless re-render.</p><h3>Summary</h3><ul><li>If you do not use children prop, every component inside the render function of a parent will re-render by default.</li><li>There are ways to prevent useless re-renders: (1) Use memo with areEqual, or (2) Use PureComponent or shouldComponentUpdate</li><li>If there are functions in your props, before using areEqual or shouldComponentUpdate: (1) Exclude them (not recommended), (2) Stringify them (not recommended), or (3) use useCallback , or (4) bind the function to the class.</li></ul><p><em>Originally published at </em><a href="https://9oelm.github.io/2019-10-02--Making-stupid-react-smart-in-re-rendering/"><em>https://9oelm.github.io/2019-10-02--Making-stupid-react-smart-in-re-rendering/</em></a><em>.</em></p><h3>Edit</h3><p>First of all, thank you for the insightful comments.</p><ol><li>The cost of stringifying the functions may be larger than the benefit of optimization itself. So don’t use stringify, really.</li><li>You should instead use useCallback in your functional component (see the comment section for an example). But still, I’m not sure how we could do that for a class component. Anybody got a good idea?</li></ol><p>Yes, and you should really take into consideration how much tradeoff your optimization could bring. In other words, the optimization could not work as you expected.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5f04b5bab327" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/making-stupid-react-smart-in-re-rendering-5f04b5bab327">Making stupid React smart in re-rendering</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>