<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Suhan Wijaya</title>
    <description>The latest articles on Forem by Suhan Wijaya (@suhanw).</description>
    <link>https://forem.com/suhanw</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F539724%2Ff1a775dc-30c9-4ffd-95ad-cd1ec4686bc4.png</url>
      <title>Forem: Suhan Wijaya</title>
      <link>https://forem.com/suhanw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/suhanw"/>
    <language>en</language>
    <item>
      <title>Intro to React Server Side Rendering</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Tue, 12 Jan 2021 13:44:39 +0000</pubDate>
      <link>https://forem.com/suhanw/intro-to-react-server-side-rendering-nh9</link>
      <guid>https://forem.com/suhanw/intro-to-react-server-side-rendering-nh9</guid>
      <description>&lt;h4&gt;
  
  
  How to build a React SSR app without any tooling or framework
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F900%2F1%2APXvYmj3eEqaRigoFGcJZTA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F900%2F1%2APXvYmj3eEqaRigoFGcJZTA.jpeg"&gt;&lt;/a&gt;Source: &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/5lnsko/programming_environment_dilbert_comic_strip_on/" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt; and Dilbert by Scott Adams&lt;/p&gt;




&lt;p&gt;This is the first in (hopefully) a series of articles to document the lessons I learned building and maintaining SSR apps.&lt;/p&gt;

&lt;p&gt;This article does not cover the pros/cons of SSR, or the pros/cons of not using tooling or frameworks (e.g., Create React App, Next.js, etc).&lt;/p&gt;

&lt;p&gt;I fully acknowledge that manually setting up build configs is painful. There is plenty of great tooling out there to abstract away these configs, so you probably don’t even need to touch any of this stuff to build awesome apps.&lt;/p&gt;

&lt;p&gt;But for those ready to embrace the pain…&lt;/p&gt;




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

&lt;p&gt;Let’s start with the basics. We will use &lt;strong&gt;React&lt;/strong&gt; , &lt;strong&gt;webpack&lt;/strong&gt; , and &lt;strong&gt;Express&lt;/strong&gt; to build an SSR app that works as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Browser sends HTTP request to server to load a page.&lt;/li&gt;
&lt;li&gt;Server receives HTTP request and turns React JSX into HTML markup.&lt;/li&gt;
&lt;li&gt;Server inserts the markup into a HTML template and sends the HTML response back to the browser.&lt;/li&gt;
&lt;li&gt;Browser renders the HTML, downloads the client-side JavaScript bundle, and “hydrates” the HTML.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also, I will focus on dev mode to keep this article short. I’m saving production mode for a future(ish 😅) article.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project structure
&lt;/h3&gt;

&lt;p&gt;Before diving into the code, let’s get situated with the project structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
+-- client
| +-- components
| | +-- App
| | | +-- index.js
| | | +-- style.less
| +-- index.js
+-- server
| +-- index.js
+-- babel.config.js
+-- package.json
+-- webpack.client.config.js
+-- webpack.server.config.js
+-- webpack.shared.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A quick rundown of the files in this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;./client/components&lt;/code&gt; contains React and CSS code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./client/index.js&lt;/code&gt; is the client-side &lt;a href="https://webpack.js.org/concepts/entry-points/" rel="noopener noreferrer"&gt;entry point&lt;/a&gt; for webpack, where we “hydrate” the HTML rendered on the server-side.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./server/index.js&lt;/code&gt; is the server-side &lt;a href="https://webpack.js.org/concepts/entry-points/" rel="noopener noreferrer"&gt;entry point&lt;/a&gt; for webpack, where we define the route to serve the HTML page.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./babel.config.js&lt;/code&gt; is the &lt;a href="https://babeljs.io/docs/en/config-files#configuration-file-types" rel="noopener noreferrer"&gt;thing&lt;/a&gt; that enables you to use React JSX and ES6+ features in the browser and Node.js. You may have seen alternative versions of this file (.babelrc, babel.config.json, etc).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./webpack.shared.config.js&lt;/code&gt; is the config that webpack uses for both client-side and server-side code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./webpack.client.config.js&lt;/code&gt; is the config specific to the client-side code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./webpack.server.config.js&lt;/code&gt; is the config specific to the server-side code.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;p&gt;Here are the dependencies (and versions) used at the time of this writing. I will also mention which relevant dependencies to install in each of the following sections.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now let’s look at each file in our project in more detail.&lt;/p&gt;




&lt;h3&gt;
  
  
  webpack
&lt;/h3&gt;

&lt;p&gt;If you are accustomed to building SPAs (Single Page Apps), you may not have needed webpack to process your server-side code. But to enable SSR, the server must be able to read React code, or specifically — JSX. This means, we now need webpack to work its magic on our server-side code. Plus, you’ll also get to use ES6+ syntax that may not be natively supported in Node.js, e.g., import and export. (Sidenote: you don’t need webpack if you choose &lt;a href="https://reactjs.org/docs/react-without-jsx.html" rel="noopener noreferrer"&gt;not to write JSX&lt;/a&gt; at all. 😬)&lt;/p&gt;

&lt;p&gt;I won’t go through every webpack option in great detail, but here is a &lt;a href="https://www.valentinog.com/blog/webpack/" rel="noopener noreferrer"&gt;great explainer&lt;/a&gt; if you are interested.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Common webpack config for client-side and server-side&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i webpack webpack-cli babel-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Annotations of the code comments above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[A]&lt;/strong&gt; For our purposes, we want to explicitly set &lt;code&gt;mode&lt;/code&gt; to &lt;strong&gt;development&lt;/strong&gt;. If we go with the default value of &lt;strong&gt;production&lt;/strong&gt; , we may lose useful console warnings/errors from libraries like React, and the error stack traces are incredibly hard to read due to code minification. Read more about &lt;strong&gt;production&lt;/strong&gt; and &lt;strong&gt;development&lt;/strong&gt; modes &lt;a href="https://webpack.js.org/configuration/mode/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[B]&lt;/strong&gt; This tells webpack to preprocess &lt;code&gt;.js&lt;/code&gt; files with &lt;code&gt;babel-loader&lt;/code&gt;, which &lt;a href="https://scotch.io/tutorials/javascript-transpilers-what-they-are-why-we-need-them#:~:text=Transpilers%2C%20or%20source%2Dto%2D,are%20said%20to%20target%20JavaScript." rel="noopener noreferrer"&gt;transpiles&lt;/a&gt; ES6+ and JSX code into JavaScript code that is readable by browsers and Node.js servers. This loader uses the options we specify in &lt;code&gt;babel.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[C]&lt;/strong&gt; This means I don’t have to type out &lt;code&gt;.js&lt;/code&gt; or &lt;code&gt;.less&lt;/code&gt; when importing files with those extensions. For example, &lt;code&gt;import App from ‘./components/App’&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Babel config&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i babel-loader @babel/core @babel/preset-env @babel/preset-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Annotations of the code comments above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[A]&lt;/strong&gt; This tells webpack to transpile ES6+ features into JS code that’s natively supported in Node.js and (most modern) browsers. Read the &lt;a href="https://babeljs.io/docs/en/babel-preset-env" rel="noopener noreferrer"&gt;docs&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[B]&lt;/strong&gt; This tells webpack to transpile React JSX into JavaScript code. Read the &lt;a href="https://babeljs.io/docs/en/babel-preset-react" rel="noopener noreferrer"&gt;docs&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Client-side webpack config&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i webpack webpack-cli webpack-merge webpack-dev-server mini-css-extract-plugin css-loader less-loader less
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Annotations of the code comments above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[A]&lt;/strong&gt; This is the entry point for the client-side code, where we render the React app into the DOM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[B]&lt;/strong&gt; This tells webpack to save the transpiled client-side JS bundle output as &lt;code&gt;./build/client/scripts/bundle.js&lt;/code&gt;. Not super important for dev mode because we are using webpack-dev-server to transpile the client-side bundle “in memory”. Per the &lt;a href="https://webpack.js.org/guides/development/#using-webpack-dev-server" rel="noopener noreferrer"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;webpack-dev-server&lt;/code&gt; doesn’t write any output files after compiling. Instead, it keeps bundle files in memory and serves them as if they were real files mounted at the server’s root path.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;[C]&lt;/strong&gt; The &lt;code&gt;publicPath&lt;/code&gt; option tells webpack where we will be serving the client-side bundle. Notice that we are using the same &lt;code&gt;clientPort&lt;/code&gt; for &lt;code&gt;devServer&lt;/code&gt;, which tells &lt;code&gt;webpack-dev-server&lt;/code&gt; to serve the client-side bundle from &lt;code&gt;http://localhost:8080/&lt;/code&gt;. And since the &lt;code&gt;filename&lt;/code&gt; option tells webpack to nest &lt;code&gt;bundle.js&lt;/code&gt; in a &lt;code&gt;scripts&lt;/code&gt; folder, the client-side bundle will be served from &lt;code&gt;http://localhost:8080/scripts/bundle.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[D]&lt;/strong&gt; &lt;a href="https://css-tricks.com/css-modules-part-1-need/" rel="noopener noreferrer"&gt;CSS modules&lt;/a&gt; and CSS preprocessors (e.g., Less, Sass) deserve an article. But in a nutshell, this piece of config tells webpack to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transpile &lt;code&gt;.less&lt;/code&gt; files into CSS code that the browser understands,&lt;/li&gt;
&lt;li&gt;allow us to &lt;code&gt;import style from ‘./style.less’&lt;/code&gt; which is scoped &lt;strong&gt;locally&lt;/strong&gt; to the component importing it (i.e., we don’t have to worry about CSS class naming collisions or specificity issues as the app grows),&lt;/li&gt;
&lt;li&gt;generate a CSS bundle that’s served separately from the JS bundle. In this instance, the &lt;code&gt;MiniCssExtractPlugin&lt;/code&gt; tells webpack to serve the CSS bundle from &lt;code&gt;http://localhost:8080/styles/bundle.css&lt;/code&gt; in dev mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;[E]&lt;/strong&gt; Remember &lt;code&gt;webpack.shared.config.js&lt;/code&gt;? This line merges &lt;code&gt;webpack.shared.config.js&lt;/code&gt; with &lt;code&gt;webpack.client.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Server-side webpack config&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Hang in there, this is the last webpack config that we’ll cover.&lt;/p&gt;

&lt;p&gt;Install the relevant dependencies (and grab a ☕️):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i webpack webpack-cli webpack-node-externals css-loader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Annotations of the code comments above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[A]&lt;/strong&gt; The default value is &lt;strong&gt;web&lt;/strong&gt;, so we need to explicitly set it to &lt;strong&gt;node&lt;/strong&gt; for webpack to work its magic on the server-side code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[B]&lt;/strong&gt; This is the entry point for the server-side code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[C]&lt;/strong&gt; This tells webpack to save the transpiled server-side JS bundle output as &lt;code&gt;./build/server/bundle.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[D]&lt;/strong&gt; This tells webpack not to include the code from &lt;code&gt;node\_modules&lt;/code&gt; in the server-side bundle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[E]&lt;/strong&gt; This tells webpack not to do any work over the CSS code on the server-side, but simply to make sure that every HTML element’s &lt;code&gt;className&lt;/code&gt; matches that in the CSS code being served on the client-side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[F]&lt;/strong&gt; Remember &lt;code&gt;webpack.shared.config.js&lt;/code&gt;? This line merges &lt;code&gt;webpack.shared.config.js&lt;/code&gt; with &lt;code&gt;webpack.server.config.js&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  React component
&lt;/h3&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;


&lt;p&gt;Let’s create a simple React component &lt;code&gt;App&lt;/code&gt;, which renders our favorite greeting with some basic styles, as well as a button that displays an alert dialog when clicked. We will render this component on the server-side and hydrate it on the client-side.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;h3&gt;
  
  
  Server-side code
&lt;/h3&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i express react react-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s create an Express server and define a route that serves an HTML page when a user visits &lt;code&gt;http://localhost:3000/&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Annotations of the code comments above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[A]&lt;/strong&gt; This turns the React component &lt;code&gt;App&lt;/code&gt; into HTML string, which we then insert in between the &lt;code&gt;div&lt;/code&gt; with the ID &lt;strong&gt;“ssr-app”.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[B]&lt;/strong&gt; Remember the &lt;code&gt;devServer&lt;/code&gt; option in &lt;code&gt;webpack.client.config.js&lt;/code&gt; to start &lt;code&gt;webpack-dev-server&lt;/code&gt; in dev mode? These script and link tags tell the browser to fetch the client-side JS and CSS bundles respectively from the webpack-dev-server running on &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Client-side code
&lt;/h3&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i react react-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the client-side entry point, we will “&lt;a href="https://reactjs.org/docs/react-dom.html#hydrate" rel="noopener noreferrer"&gt;hydrate&lt;/a&gt;” the React component that was SSR-ed into the root DOM container with the ID &lt;strong&gt;“ssr-app”&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Per the &lt;a href="https://reactjs.org/docs/react-dom-server.html#rendertostring" rel="noopener noreferrer"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you call &lt;a href="https://reactjs.org/docs/react-dom.html#hydrate" rel="noopener noreferrer"&gt;&lt;em&gt;ReactDOM.hydrate()&lt;/em&gt;&lt;/a&gt; on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So in this example, the client-side code simply attaches the button’s click handler without having to re-render any markup in the &lt;code&gt;App&lt;/code&gt; component.&lt;/p&gt;




&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;Install the relevant dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i rimraf webpack webpack-cli webpack-dev-server npm-run-all nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the &lt;code&gt;scripts&lt;/code&gt; key in the &lt;code&gt;package.json&lt;/code&gt; file, where we define several &lt;code&gt;npm&lt;/code&gt; scripts to build and start the app in dev mode.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Let’s look at each of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;clear&lt;/code&gt; — This uses &lt;a href="https://github.com/isaacs/rimraf" rel="noopener noreferrer"&gt;rimraf&lt;/a&gt; to delete the &lt;code&gt;./build&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build:server&lt;/code&gt; — This tells webpack to build the server-side code and save the bundle output to &lt;code&gt;./build/server/bundle.js&lt;/code&gt; (as per &lt;code&gt;./webpack.server.config.js&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start:server&lt;/code&gt; — This starts the Express server on &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dev:server&lt;/code&gt; — This uses &lt;a href="https://github.com/remy/nodemon" rel="noopener noreferrer"&gt;nodemon&lt;/a&gt; to monitor any file changes in the working directory (minus &lt;code&gt;./build&lt;/code&gt;), and &lt;a href="https://dev.to/scottw/npm-run-all-b7e-temp-slug-8424854"&gt;npm-run-all&lt;/a&gt; to re-run &lt;code&gt;clear&lt;/code&gt;, &lt;code&gt;build:server&lt;/code&gt;, and &lt;code&gt;start:server&lt;/code&gt; whenever there are file changes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dev:client&lt;/code&gt; — This tells webpack to “build” the client-side code, save the bundle output “in memory”, and serve it from &lt;code&gt;http://localhost:8080&lt;/code&gt; (as per &lt;code&gt;./webpack.client.config.js&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dev&lt;/code&gt; — This runs all of the above with a single command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; in the terminal to spin up the SSR app. Open up &lt;code&gt;http://localhost:3000&lt;/code&gt; in your browser. 🎉🥳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Aht6aRr0glttBE5TlouMJJQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Aht6aRr0glttBE5TlouMJJQ.png"&gt;&lt;/a&gt;Server-side rendering and client-side hydration&lt;/p&gt;

&lt;p&gt;And click on the button &lt;code&gt;Say Hello Back!&lt;/code&gt; 🙌🎊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AJcnDOG4whmExaBhNoyG8Vg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AJcnDOG4whmExaBhNoyG8Vg.png"&gt;&lt;/a&gt;Clicking the button triggers the alert dialog&lt;/p&gt;

&lt;p&gt;Now, let’s disable client-side JavaScript…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F722%2F1%2A43qx5zcj8QnwSjXQT-Nhsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F722%2F1%2A43qx5zcj8QnwSjXQT-Nhsw.png"&gt;&lt;/a&gt;Disable client-side JavaScript&lt;/p&gt;

&lt;p&gt;…and refresh the page. IT’S NOT A BLANK PAGE! 🤯&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AfFgBAnbm-9c3gN6J_yA1eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AfFgBAnbm-9c3gN6J_yA1eg.png"&gt;&lt;/a&gt;Server-side rendered page&lt;/p&gt;

&lt;p&gt;Sidenote: nothing will happen if you click on the button. That’s because the event handlers are attached by the client-side code (aka “hydration”). Recall the &lt;a href="https://reactjs.org/docs/react-dom-server.html#rendertostring" rel="noopener noreferrer"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you call &lt;a href="https://reactjs.org/docs/react-dom.html#hydrate" rel="noopener noreferrer"&gt;&lt;em&gt;ReactDOM.hydrate()&lt;/em&gt;&lt;/a&gt; on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And since we disabled client-side JavaScript, what you see is just plain HTML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F894%2F1%2AxGp1Ds4XtlabyFoGwI2G1A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F894%2F1%2AxGp1Ds4XtlabyFoGwI2G1A.jpeg"&gt;&lt;/a&gt;Source: &lt;a href="https://www.thecoderpedia.com/blog/programming-memes/" rel="noopener noreferrer"&gt;CoderPedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In future(ish 😅🤞🏻) articles, I plan to cover more advanced features like routing, data fetching, caching, code-splitting, lazy-loading, and deploying a production app.&lt;/p&gt;




&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.valentinog.com/blog/webpack/" rel="noopener noreferrer"&gt;A mostly complete guide to webpack 5&lt;/a&gt; by &lt;a href="https://twitter.com/gagliardi_vale" rel="noopener noreferrer"&gt;Valentino Gagliardi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://scotch.io/tutorials/javascript-transpilers-what-they-are-why-we-need-them#:~:text=Transpilers,%20or%20source-to-,are%20said%20to%20target%20JavaScript." rel="noopener noreferrer"&gt;JavaScript Transpilers: What &amp;amp; Why&lt;/a&gt; by &lt;a href="https://medium.com/u/1baf735d9bdc" rel="noopener noreferrer"&gt;Peleke Sengstacke&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://css-tricks.com/css-modules-part-1-need/" rel="noopener noreferrer"&gt;What are CSS Modules and why do we need them?&lt;/a&gt; by &lt;a href="https://medium.com/u/aae529a3f8b0" rel="noopener noreferrer"&gt;Robin Rendle&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/suhanw/decouple-data-from-ui-with-react-hooks-3amn"&gt;Decouple Data from UI with React Hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/suhanw/decouple-data-from-ui-in-react-part-2-4amk"&gt;Decouple Data from UI in React Part 2: A further exploration of the Hooks, Render Props, and HOC patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/suhanw/accessible-ui-stop-making-clickable-divs-g8k"&gt;Accessible UI: Stop making clickable DIVs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;📫 &lt;em&gt;Let’s connect on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Decouple Data from UI in React Part 2</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Tue, 29 Dec 2020 21:47:57 +0000</pubDate>
      <link>https://forem.com/suhanw/decouple-data-from-ui-in-react-part-2-4amk</link>
      <guid>https://forem.com/suhanw/decouple-data-from-ui-in-react-part-2-4amk</guid>
      <description>&lt;h4&gt;
  
  
  A further exploration of the Hooks, Render Props, and HOC patterns
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F556%2F1%2AgoD09hSrSRRjYBjiCrimJQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F556%2F1%2AgoD09hSrSRRjYBjiCrimJQ.jpeg"&gt;&lt;/a&gt;c. 1512, Oil on canvas, Source: &lt;a href="https://programming-memes.com/do-you-like-spaghetti/" rel="noopener noreferrer"&gt;programming-memes.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In &lt;a href="https://dev.to/suhanw/decouple-data-from-ui-with-react-hooks-3amn"&gt;Part 1&lt;/a&gt;, I presented an approach to decouple the data fetching/management layer from the UI, which would free us from being locked into any particular data library or framework. Let’s call this &lt;strong&gt;Approach A&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach A. Custom Hook
&lt;/h3&gt;

&lt;p&gt;Let’s create a custom hook — &lt;code&gt;useSomeData&lt;/code&gt; — that returns the properties &lt;code&gt;someData&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt; regardless of the data fetching/management logic. The following are 3 different implementations of &lt;code&gt;useSomeData&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With Fetch API and component state:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;With Redux:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;With Apollo GraphQL:&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The 3 implementations above are &lt;strong&gt;interchangeable&lt;/strong&gt; without having to modify this UI component:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;But, as &lt;a href="https://medium.com/u/3efad7746b00" rel="noopener noreferrer"&gt;Julius Koronci&lt;/a&gt; correctly pointed out, while the data fetching/management logic is decoupled, the &lt;code&gt;SomeComponent&lt;/code&gt; UI is still coupled to the &lt;code&gt;useSomeData&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;In other words, even though we can reuse &lt;code&gt;useSomeData&lt;/code&gt; without &lt;code&gt;SomeComponent&lt;/code&gt;, &lt;strong&gt;we cannot reuse&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;SomeComponent&lt;/code&gt; without&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;useSomeData&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Perhaps this is where Render Props and Higher Order Components do a better job at enforcing the separation of concerns (thanks again to Julius for highlighting this).&lt;/p&gt;




&lt;h3&gt;
  
  
  Approach B. Render Props
&lt;/h3&gt;

&lt;p&gt;Instead of a custom hook that returns &lt;code&gt;someData&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;, let’s create a Render Props component — &lt;code&gt;SomeData&lt;/code&gt; — that wraps around a function (i.e., children needs to be a function), implements the data logic, and passes in &lt;code&gt;someData&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt; into the function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can replace line 4 in the snippet above with Redux, Apollo GraphQL, or any data fetching/management layer of your choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We can now reuse&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;SomeComponent&lt;/code&gt; (UI component) without&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;SomeData&lt;/code&gt; (Render Props component). We can also reuse&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;SomeData&lt;/code&gt; without&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;SomeComponent&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Approach C. Higher Order Components (HOC)
&lt;/h3&gt;

&lt;p&gt;Let’s create a HOC — &lt;code&gt;withSomeData&lt;/code&gt; — that accepts a React component as an argument, implements the data logic, and passes &lt;code&gt;someData&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt; as props into the wrapped React component.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can replace line 5 in the snippet above with Redux, Apollo GraphQL, or any data fetching/management layer of your choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We can now reuse&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;SomeComponent&lt;/code&gt; (UI component) without&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;withSomeData&lt;/code&gt; (HOC). We can also reuse&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;withSomeData&lt;/code&gt; without&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;SomeComponent&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Today I learned.&lt;/p&gt;

&lt;p&gt;Which approach do you prefer and why?&lt;/p&gt;




&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://blog.bitsrc.io/understanding-react-render-props-and-hoc-b37a9576e196" rel="noopener noreferrer"&gt;Understanding React Render Props and HOC&lt;/a&gt; by &lt;a href="https://medium.com/u/9c555799c00e" rel="noopener noreferrer"&gt;Aditya Agarwal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-props" rel="noopener noreferrer"&gt;React Hooks: What’s going to happen to render props?&lt;/a&gt; by &lt;a href="https://medium.com/u/db72389e89d8" rel="noopener noreferrer"&gt;Kent C. Dodds&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.richardkotze.com/coding/hoc-vs-render-props-react" rel="noopener noreferrer"&gt;Higher-order components vs Render Props&lt;/a&gt; by &lt;a href="https://medium.com/u/e503a3e5ff3e" rel="noopener noreferrer"&gt;Richard Kotze&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/javascript-in-plain-english/intro-to-react-server-side-rendering-3c2af3782d08" rel="noopener noreferrer"&gt;Intro to React Server Side Rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/suhanw/decouple-data-from-ui-with-react-hooks-3amn"&gt;Decouple Data from UI with React Hooks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;📫 &lt;em&gt;Let’s connect on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>softwaredesign</category>
    </item>
    <item>
      <title>Decouple SDK Code From Core React Code</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Sat, 26 Dec 2020 18:04:48 +0000</pubDate>
      <link>https://forem.com/suhanw/decouple-sdk-code-from-core-react-code-2c3g</link>
      <guid>https://forem.com/suhanw/decouple-sdk-code-from-core-react-code-2c3g</guid>
      <description>&lt;h4&gt;
  
  
  And reduce the size of your future PRs with the Open/Closed Principle
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NbHtilB9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ap37cH3mNXH_Z2wtXprcT2Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NbHtilB9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ap37cH3mNXH_Z2wtXprcT2Q.jpeg" alt=""&gt;&lt;/a&gt;KNOW YOUR ENEMY&lt;br&gt; (image by &lt;a href="https://unsplash.com/photos/CatcixzdUcg"&gt;Klara Kulikova&lt;/a&gt;, meme from &lt;a href="https://programming-memes.com/spaghetti-code-know-your-enemy/"&gt;Programming Memes&lt;/a&gt;)&lt;/p&gt;




&lt;p&gt;Suppose I use an external service provider to process payments for my E-commerce app, and I need to embed some external SDK code to integrate the payment service into my app.&lt;/p&gt;

&lt;p&gt;In this oversimplified example, let’s say the payment service is responsible for checking whether a given payment method (e.g, Apple Pay and Google Pay) is available based on the customer’s device, region, etc. While my “core” UI component &lt;code&gt;PaymentOptions&lt;/code&gt; is responsible for rendering the available payment methods as options. Lastly, I want the flexibility of adding new payment methods in the future (for 📈💰reasons).&lt;/p&gt;

&lt;p&gt;I can write it this way.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;However, the UI code is tightly coupled with the external code from the payment service, i.e., &lt;strong&gt;I have to modify the&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;PaymentOptions&lt;/code&gt; component in order to add a new payment method or to make SDK updates.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;I can perhaps break out the SDK code into a separate hook.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;However, I &lt;em&gt;still&lt;/em&gt; have to modify&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;PaymentOptions&lt;/code&gt;&lt;/strong&gt;  &lt;strong&gt;and any other components that share the&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;usePaymentMethods&lt;/code&gt; hook if I wanted to add, for example,&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;isPaypalAvailable&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;To minimize the size of future PRs, I’ve been thinking about the Open/Closed Principle, the “O” in SOLID (check out this excellent &lt;a href="https://medium.com/better-programming/revisiting-solid-927e6a5202d3"&gt;explainer&lt;/a&gt;): “&lt;em&gt;A software artifact should be open for extension but closed for modification.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my own words: &lt;em&gt;I should design this feature in such a way that I don’t have to touch any of the original code I wrote (closed for modification) if I were to add new payment methods in the future (open for extension).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here’s my take on this principle. Let’s separate the payment service into its own module: a simple object where each key represents a payment method. Every payment method key points to an object with an &lt;code&gt;isAvailable&lt;/code&gt; property (a function that uses the SDK code) and a &lt;code&gt;component&lt;/code&gt; property (the UI component for the payment option).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Import &lt;code&gt;paymentServiceModule&lt;/code&gt; into the &lt;code&gt;PaymentOptions&lt;/code&gt; component.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;PaymentOptions&lt;/code&gt; is now decoupled from the SDK implementation details, and is ignorant of the particular payment methods.&lt;/p&gt;

&lt;p&gt;When I want to extend this feature with a new payment method (i.e., PayPal), &lt;strong&gt;I simply slot in a new key/value pair to &lt;code&gt;paymentServiceModule&lt;/code&gt; without having to modify either the &lt;code&gt;PaymentOptions&lt;/code&gt; component or the original payment methods&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The UI code should in theory also be protected against modification if I were to change payment service providers (for 💸 reasons) as long as the payment method’s duck typing remains unchanged.&lt;/p&gt;

&lt;p&gt;Am I applying the Open/Closed Principle correctly? Curious to learn other React or JavaScript patterns in the wild that follow this principle.&lt;/p&gt;




&lt;h3&gt;
  
  
  Bonus
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;paymentServiceModule&lt;/code&gt;, lazy load each payment option using the &lt;a href="https://reactjs.org/docs/code-splitting.html#reactlazy"&gt;&lt;code&gt;React.lazy&lt;/code&gt;&lt;/a&gt; API.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;In &lt;code&gt;PaymentOptions&lt;/code&gt;, wrap each payment option in &lt;code&gt;Suspense&lt;/code&gt;, to lazy load the component based on availability.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://medium.com/javascript-in-plain-english/a-first-step-to-improve-your-code-before-diving-into-domain-driven-design-or-the-clean-architecture-90da4a80d863"&gt;A First Step to Improve Your Code Before Diving into Domain Driven Design or the Clean Architecture&lt;/a&gt; by &lt;a href="https://medium.com/u/57de27e2974f"&gt;Andréas Hanss&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/better-programming/revisiting-solid-927e6a5202d3"&gt;Revisiting SOLID&lt;/a&gt; by &lt;a href="https://medium.com/u/12cc371abade"&gt;Matthew Lucas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/javascript-in-plain-english/intro-to-react-server-side-rendering-3c2af3782d08"&gt;Intro to React Server Side Rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/suhanw/decouple-data-from-ui-with-react-hooks-3amn"&gt;Decouple Data from UI with React Hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/javascript-in-plain-english/how-to-decouple-data-from-ui-in-react-d6b1516f4f0b"&gt;Decouple Data from UI in React Part 2: A further exploration of the Hooks, Render Props, and HOC patterns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;📫 &lt;em&gt;Let’s connect on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>softwaredesign</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Traditional versus Arrow functions in JavaScript Classes</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Thu, 17 Dec 2020 22:28:01 +0000</pubDate>
      <link>https://forem.com/suhanw/traditional-versus-arrow-functions-in-javascript-classes-iil</link>
      <guid>https://forem.com/suhanw/traditional-versus-arrow-functions-in-javascript-classes-iil</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1280%2F1%2A-IeFjTYIltNhNfNW4hE5YA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1280%2F1%2A-IeFjTYIltNhNfNW4hE5YA.jpeg" alt="The two states of every programmer"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://programmerhumour.tumblr.com/image/633387776634732544" rel="noopener noreferrer"&gt;Programmer Humor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;This is a spiritual sequel to &lt;a href="https://medium.com/the-innovation/a-method-destructured-from-an-object-loses-its-original-context-21e73cf1451f" rel="noopener noreferrer"&gt;this article&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Create a class with a method using Traditional function like so. Let’s call this &lt;strong&gt;Approach A&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// APPROACH A&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someValue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Traditional function&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an instance of that class. When invoking the method on the instance, &lt;code&gt;this&lt;/code&gt; refers to the instance. So far, it’s behaving as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// logs 'someValue'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, as soon as we assign the method to a variable and call that function variable, the method loses its context, and you get &lt;code&gt;Uncaught TypeError: Cannot read property ‘someProp’ of undefined&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;funcVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;funcVariable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// logs error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK.&lt;/p&gt;

&lt;p&gt;Now, let’s create the class with a method using Arrow function like so. Let’s call this &lt;strong&gt;Approach B&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// APPROACH B&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someValue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Arrow function&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This now works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;funcVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;funcVariable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// logs 'someValue'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// destructuring also works!&lt;/span&gt;
&lt;span class="nf"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// logs 'someValue'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why, JavaScript, why?
&lt;/h2&gt;

&lt;p&gt;As per &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain" rel="noopener noreferrer"&gt;MDN docs&lt;/a&gt;, “the class keyword is introduced in ES2015, but is syntactical sugar, JavaScript remains prototype-based.” So if we were to write in pre-ES6 syntax, &lt;strong&gt;Approach A&lt;/strong&gt; looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Equivalent to APPROACH A&lt;/span&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;SomeClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someValue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The property &lt;code&gt;someMethod&lt;/code&gt; is defined on the constructor function’s &lt;code&gt;prototype&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1036%2F1%2AdCPPZGSH9Qf_c7RdTFa2Ag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1036%2F1%2AdCPPZGSH9Qf_c7RdTFa2Ag.png" alt="Chrome Dev Console"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;But not on the &lt;code&gt;instance&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1072%2F1%2AI9XIUW-edxdWn_Y8I-8qRQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1072%2F1%2AI9XIUW-edxdWn_Y8I-8qRQ.png" alt="Chrome Dev Console"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;You can access &lt;code&gt;instance.someMethod&lt;/code&gt; through &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain" rel="noopener noreferrer"&gt;prototypal inheritance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But when you assign &lt;code&gt;instance.someMethod&lt;/code&gt; to another variable, the function variable loses its context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Further, since &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Class_body_and_method_definitions" rel="noopener noreferrer"&gt;“code within the &lt;code&gt;class&lt;/code&gt; body's syntactic boundary is always executed in strict mode”&lt;/a&gt;, &lt;code&gt;this&lt;/code&gt; will be undefined instead of defaulting to &lt;code&gt;window&lt;/code&gt; or &lt;code&gt;global&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;OK.&lt;/p&gt;

&lt;p&gt;Now, &lt;strong&gt;Approach B&lt;/strong&gt; looks like this in pre-ES6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Equivalent to APPROACH B&lt;/span&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;SomeClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someValue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;_that&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_that&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someProp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The property &lt;code&gt;someMethod&lt;/code&gt; is not defined on the constructor function’s &lt;code&gt;prototype&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F648%2F1%2AAxs8fo1y575ZiMwsy5P02Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F648%2F1%2AAxs8fo1y575ZiMwsy5P02Q.png" alt="Chrome Dev Console"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Instead, it is defined on the &lt;code&gt;instance&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1420%2F1%2AyUkx782Yo1M1fBe8np9mDg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1420%2F1%2AyUkx782Yo1M1fBe8np9mDg.png" alt="Chrome Dev Console"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Further, an Arrow function is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Description" rel="noopener noreferrer"&gt;bound to its surrounding lexical context by default&lt;/a&gt; (where it physically sits in the code), which seems equivalent to a Traditional function having access to an outer function variable that points to &lt;code&gt;this&lt;/code&gt; (i.e., &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures" rel="noopener noreferrer"&gt;closure&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hence, even when you assign &lt;code&gt;instance.someMethod&lt;/code&gt; to another variable, the function variable remains bound to the instance context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Note: I’m not 100% sure about the actual ‘under the hood’ mechanism by which Arrow functions derive &lt;code&gt;this&lt;/code&gt;, so feel free to comment if you do know.&lt;/p&gt;

&lt;p&gt;In any case, I went down this rabbit hole because I’ve been using Arrow functions for writing methods in classical React components, instead of binding Traditional functions (i.e., &lt;code&gt;this.someMethod.bind(this)&lt;/code&gt;) in the &lt;code&gt;constructor&lt;/code&gt; or when passing it down as prop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* some state */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Arrow function&lt;/span&gt;
        &lt;span class="c1"&gt;// will have access to `this.state`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// may attach `this.someMethod` as an event handler or &lt;/span&gt;
        &lt;span class="c1"&gt;// pass it down as a prop to child components&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not endorsing one approach or the other, just describing the difference. Oh, and guess &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Browser_compatibility" rel="noopener noreferrer"&gt;which browser&lt;/a&gt; is completely irrelevant to this whole discussion.&lt;/p&gt;




&lt;p&gt;📫 &lt;em&gt;Hit me up on &lt;a href="https://www.linkedin.com/in/suhanwijaya/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://twitter.com/suhanw" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>coding</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Decouple Data from UI with React Hooks</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Mon, 23 Nov 2020 09:53:55 +0000</pubDate>
      <link>https://forem.com/suhanw/decouple-data-from-ui-with-react-hooks-3amn</link>
      <guid>https://forem.com/suhanw/decouple-data-from-ui-with-react-hooks-3amn</guid>
      <description>&lt;h3&gt;
  
  
  And how I “program to an interface” with JavaScript functions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qmTmG9wn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AYsy1EpS9hF5J3qnkT5TX3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qmTmG9wn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AYsy1EpS9hF5J3qnkT5TX3A.png" alt=""&gt;&lt;/a&gt;Source: &lt;a href="https://imgur.com/gallery/CgWZFId"&gt;Imgur&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I‘m certain you have seen (or written) this common React pattern: (a) render a placeholder/ loader/spinner while some data is fetched via AJAX, then (b) re-render the component based on the data received. Let’s write a functional component leveraging the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;Fetch API&lt;/a&gt; to accomplish this.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;Let’s say my app grows, and there are X components that use the same data fetching logic because… reasons. To avoid spamming the server with data requests, I decide to use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage"&gt;Local Storage&lt;/a&gt; to cache the data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OK… does that mean I need to update the data logic&lt;/strong&gt;  &lt;strong&gt;X times? 😬😱&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nope, let’s &lt;a href="https://medium.com/better-programming/kiss-dry-and-code-principles-every-developer-should-follow-b77d89f51d74"&gt;DRY it up&lt;/a&gt; by writing a custom hook &lt;code&gt;useSomeData&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The components that share this data logic now look concise.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;OK… DRY code is great, but so what?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s say my app becomes complex, so I decide to use Redux to handle AJAX requests and maintain a global app state. I simply update the implementation of &lt;code&gt;useSomeData&lt;/code&gt; &lt;em&gt;without touching the UI components&lt;/em&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then GraphQL comes along and I jump on the bandwagon. Again, I simply update the implementation of &lt;code&gt;useSomeData&lt;/code&gt; &lt;em&gt;without touching the UI components&lt;/em&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;Rinse and repeat whenever I’m compelled to update the data layer with the latest/hottest state management framework or API paradigm.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To me, this looks a lot like the classic Dependency Inversion Principle, the “D” in SOLID (check out this excellent &lt;a href="https://medium.com/better-programming/revisiting-solid-927e6a5202d3"&gt;explainer&lt;/a&gt; by &lt;a href="https://medium.com/u/12cc371abade"&gt;Matthew Lucas&lt;/a&gt;). While this is not OOP by any means, where we formally define an abstract &lt;code&gt;Interface&lt;/code&gt; and create a concrete &lt;code&gt;Class&lt;/code&gt; that implements that &lt;code&gt;Interface&lt;/code&gt;, I would argue that there is a de facto “interface” that &lt;code&gt;useSomeData&lt;/code&gt; provides to the various UI components using it. In this example, the UI doesn’t care how &lt;code&gt;useSomeData&lt;/code&gt; works, as long as it receives &lt;code&gt;someData&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt; from the hook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So in theory, this frees the UI from being locked into any particular implementation of the data layer, and enables migrating to new implementations (frameworks/libraries/etc) without having to update the UI code, as long as the “interface” contract is honored.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Curious to hear your thoughts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0V9t6Tdv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/540/1%2AF1CfUAi51VQA4NJd3Fj_cA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0V9t6Tdv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/540/1%2AF1CfUAi51VQA4NJd3Fj_cA.jpeg" alt=""&gt;&lt;/a&gt;Source: &lt;a href="https://www.pinterest.com/pin/333759022356307210/"&gt;Pinterest&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; The &lt;a href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0"&gt;Container pattern&lt;/a&gt;, &lt;a href="https://reactjs.org/docs/render-props.html"&gt;Render Props&lt;/a&gt;, and &lt;a href="https://reactjs.org/docs/higher-order-components.html"&gt;HOC&lt;/a&gt; are popular options to decouple the data layer from the UI layer for classical components. This article is not meant to be a debate as to whether Hooks is better or worse. I’m simply sharing how I learned to use Hooks to apply the same separation of concerns.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/javascript-in-plain-english/how-to-decouple-data-from-ui-in-react-d6b1516f4f0b"&gt;Decouple Data from UI in React Part 2: A further exploration of the Hooks, Render Props, and HOC patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/javascript-in-plain-english/intro-to-react-server-side-rendering-3c2af3782d08"&gt;Intro to React Server Side Rendering&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;📫 &lt;em&gt;Let’s connect on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>softwaredesign</category>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Async/await is awesome, but don’t abandon Promises</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Sun, 15 Nov 2020 12:26:56 +0000</pubDate>
      <link>https://forem.com/suhanw/async-await-is-awesome-but-don-t-abandon-promises-47po</link>
      <guid>https://forem.com/suhanw/async-await-is-awesome-but-don-t-abandon-promises-47po</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VzvjM8T1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/960/1%2AUTN8LzorPrLQQ2HLnUDbnA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VzvjM8T1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/960/1%2AUTN8LzorPrLQQ2HLnUDbnA.jpeg" alt=""&gt;&lt;/a&gt;Shoutout to &lt;a href="https://medium.com/u/4c5633187eea"&gt;Cassidy Williams&lt;/a&gt; 😀&lt;/p&gt;




&lt;p&gt;Let’s create a button that will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;perform an expensive synchronous operation,&lt;/li&gt;
&lt;li&gt;fire 2 AJAX requests, and&lt;/li&gt;
&lt;li&gt;update the DOM based on the AJAX responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the markup.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here are the functions. Let’s also measure the duration of each operation with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure"&gt;Performance API&lt;/a&gt;, which visualizes when and how long each function executes on the Chrome DevTools Performance Timeline. (Thanks to &lt;a href="https://jsonplaceholder.typicode.com"&gt;JSONPlaceholder&lt;/a&gt; for the dummy endpoints.)&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;You’re still here? Good, here comes the interesting part: writing the &lt;code&gt;onclick&lt;/code&gt; handler for the button. Since all the cool kids are doing it, let’s use &lt;code&gt;async / await&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;someSyncOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Expensive sync operation &lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchPost&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// AJAX request #1&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commentsJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchComments&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// AJAX request #2&lt;/span&gt;

   &lt;span class="nx"&gt;appendPostDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;appendCommentsDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the Performance Timeline after clicking the button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sy0tRQHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AIPbydXJik0QO9KfFCcx97g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sy0tRQHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AIPbydXJik0QO9KfFCcx97g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a closer look.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A-S-hhVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AAfxib_uy8WZ53t31PLEX1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A-S-hhVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AAfxib_uy8WZ53t31PLEX1w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Makes sense, plenty of articles out there about how &lt;code&gt;async / await&lt;/code&gt; turns asynchronous code into blocking code. FYI, each bar is about 2 seconds when throttling the network to “Slow 3G”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So a total execution time of 6 seconds.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;OK. The &lt;code&gt;fetchPost&lt;/code&gt; and &lt;code&gt;fetchComments&lt;/code&gt; can be executed in parallel, so let’s use the &lt;code&gt;await Promise.all&lt;/code&gt; combo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;someSyncOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;fetchPost&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
    &lt;span class="nx"&gt;fetchComments&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nx"&gt;appendPostDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;appendCommentsDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tfpcrWHf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1010/1%2A37EwgrRI3pE2GHO9axxQpA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tfpcrWHf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1010/1%2A37EwgrRI3pE2GHO9axxQpA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The total execution time is now 4 seconds since &lt;code&gt;fetchPost&lt;/code&gt; and &lt;code&gt;fetchComments&lt;/code&gt; execute in parallel.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;OK. Since &lt;code&gt;someSyncOperation&lt;/code&gt; is not dependent on the AJAX requests, let’s see if moving it to the last line in the function speeds things up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;fetchPost&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
    &lt;span class="nx"&gt;fetchComments&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nx"&gt;appendPostDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;appendCommentsDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;someSyncOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RTLugxuE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALIFtuI-vycSo2BLz15jZVg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RTLugxuE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALIFtuI-vycSo2BLz15jZVg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nope, the total execution time is still 4 seconds.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;OK. It’s time to go “full &lt;code&gt;Promise&lt;/code&gt;”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;fetchPost&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;fetchComments&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;appendPostDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;appendCommentsDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;someSyncOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mLmRtNpV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1000/1%2AsBJ0Vh_BHYVCzm4BF0dQoQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mLmRtNpV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1000/1%2AsBJ0Vh_BHYVCzm4BF0dQoQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Going “full &lt;code&gt;Promise&lt;/code&gt;” cuts total execution time to 2 seconds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The reason why this works deserves its own article, but &lt;a href="http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D"&gt;here is an awesome explainer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today I learned.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VFGAiHyK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/720/1%2A-WWI7e_QvvXBYp7BPzw0PA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VFGAiHyK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/720/1%2A-WWI7e_QvvXBYp7BPzw0PA.jpeg" alt=""&gt;&lt;/a&gt;Source: &lt;a href="https://programmerhumour.tumblr.com/post/633961754778533888/google-my-saviour"&gt;Programmer Humor&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  Bonus
&lt;/h4&gt;

&lt;p&gt;For the die-hard &lt;code&gt;async / await&lt;/code&gt; fans out there, I learned (literally on the day of writing this story) that the following snippet actually does the same thing. Credit to &lt;a href="https://medium.com/better-programming/an-extremely-easy-tip-to-improve-web-performance-with-async-await-b609e7e65744"&gt;this article&lt;/a&gt; by &lt;a href="https://medium.com/u/994dcd5bc2e8"&gt;Moon&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetchPost&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commentsPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetchComments&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;someSyncOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;postPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commentsJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;commentsPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;appendPostDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;appendCommentsDOM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentsJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;📫 &lt;em&gt;Hit me up on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ui</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>promises</category>
    </item>
    <item>
      <title>Accessible UI: Stop making clickable DIVs</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Mon, 09 Nov 2020 15:34:27 +0000</pubDate>
      <link>https://forem.com/suhanw/accessible-ui-stop-making-clickable-divs-g8k</link>
      <guid>https://forem.com/suhanw/accessible-ui-stop-making-clickable-divs-g8k</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nk5lMcVF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/1%2A1rz1gDWrCac6zYoUnleaaQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nk5lMcVF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/1%2A1rz1gDWrCac6zYoUnleaaQ.jpeg" alt=""&gt;&lt;/a&gt;Source: &lt;a href="https://makeameme.org/meme/div-tags-div"&gt;Make a Meme&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used to think that accessibility is at best a UX improvement, and at worst “compliance work”. But as the pandemic turned &lt;a href="https://www.boxed.com"&gt;Boxed.com&lt;/a&gt; into an essential service for many of our customers, I have read a good number of heartbreaking customer service tickets that revealed my biases and the unintended exclusions caused by my code. Now, I’m convinced that making the web accessible is the &lt;em&gt;right thing to do.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Accessibility is a broad topic, and a subset of loftier &lt;a href="https://www.microsoft.com/design/inclusive/"&gt;inclusive design&lt;/a&gt; principles that I won’t pretend to be an expert on. I’m just sharing one of the many a11y lessons I learned as a developer.&lt;/p&gt;

&lt;p&gt;So let’s move on to the main topic.&lt;/p&gt;

&lt;p&gt;We love our &lt;code&gt;div&lt;/code&gt; tags. But, simply from a developer experience standpoint without even discussing the merits of &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Semantics#Semantics_in_HTML"&gt;semantic HTML&lt;/a&gt; (which deserves its own article), &lt;strong&gt;a&lt;/strong&gt;  &lt;strong&gt;&lt;code&gt;button&lt;/code&gt; is &lt;em&gt;more accessible with less code&lt;/em&gt; compared to a clickable &lt;code&gt;div&lt;/code&gt;&lt;/strong&gt;. To illustrate, let’s go ahead and create a clickable div.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;do something&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not good enough, we need to visually indicate through the cursor type that the div is clickable (which apparently is also &lt;a href="https://medium.com/simple-human/buttons-shouldnt-have-a-hand-cursor-b11e99ca374b"&gt;debatable&lt;/a&gt;). Let’s add some CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.someDiv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'someDiv'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not good enough, we need to verbally indicate through screen readers that the &lt;code&gt;div&lt;/code&gt; is a clickable button, and it needs to be keyboard accessible via Tabbing navigation. Let’s add &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role"&gt;role&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex"&gt;tabindex&lt;/a&gt; attributes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'someDiv'&lt;/span&gt; &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;'button'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not good enough, the &lt;code&gt;div&lt;/code&gt; also needs to be keyboard accessible via Enter and Space Bar keys. Let’s add more JavaScript (which may not even be 100% &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values#Whitespace_keys"&gt;cross-browser compatible&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;do something&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onkeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So finally, we end up with this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.someDiv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'someDiv'&lt;/span&gt; &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;'button'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;do something&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Space Bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onkeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e8Ea7aov--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/894/1%2AmQeROU_hw38oCDgFGZnzLw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e8Ea7aov--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/894/1%2AmQeROU_hw38oCDgFGZnzLw.jpeg" alt=""&gt;&lt;/a&gt;Source: &lt;a href="https://www.thecoderpedia.com/blog/programming-memes/"&gt;CoderPedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whereas, the &lt;code&gt;button&lt;/code&gt; version that’s &lt;em&gt;equally accessible&lt;/em&gt; looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Click here&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;do something&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s your approach to creating clickable UI components? Let me know in the comments.&lt;/p&gt;

&lt;p&gt;Note: I decided not to discuss aria attributes because I think they deserve their own article.&lt;/p&gt;

&lt;p&gt;📫 &lt;em&gt;Hit me up on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Missing cookie in HTTP request when using Fetch API</title>
      <dc:creator>Suhan Wijaya</dc:creator>
      <pubDate>Mon, 02 Nov 2020 13:02:48 +0000</pubDate>
      <link>https://forem.com/suhanw/missing-cookie-in-http-request-when-using-fetch-api-824</link>
      <guid>https://forem.com/suhanw/missing-cookie-in-http-request-when-using-fetch-api-824</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KHFpmDdn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALNmccGUYREE_8COw-QeQqQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KHFpmDdn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALNmccGUYREE_8COw-QeQqQ.jpeg" alt=""&gt;&lt;/a&gt;Image source: &lt;a href="https://programmerhumour.tumblr.com/image/630496229395218432"&gt;Programmer Humor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies"&gt;explainer&lt;/a&gt; of how cookies work. TLDR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser sends HTTP request to server.&lt;/li&gt;
&lt;li&gt;Server sends HTTP response with &lt;code&gt;Set-Cookie: cookie=monster&lt;/code&gt; header, which sets the cookie in the browser.&lt;/li&gt;
&lt;li&gt;Every subsequent request the browser sends to the server will have the &lt;code&gt;Cookie: cookie=monster&lt;/code&gt; header.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I store a CSRF token in a cookie, which is used by the server to validate client-side HTTP &lt;code&gt;POST&lt;/code&gt; requests. The server responds with a 403 if the cookie is missing in the HTTP request.&lt;/p&gt;

&lt;p&gt;On the client-side, I have been using the &lt;a href="https://github.com/lquixada/cross-fetch"&gt;cross-fetch&lt;/a&gt; package via the &lt;strong&gt;ponyfill&lt;/strong&gt; approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cross-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/some-route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* some payload */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One day, I decided to switch to the &lt;strong&gt;polyfill&lt;/strong&gt; approach in order to use the native &lt;code&gt;window.fetch&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cross-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/some-route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* some payload */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A bunch of users started getting 403s.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1Ij3ZWWB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2ADNVHxZtaNDbGgbIKqEtUMQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1Ij3ZWWB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/300/1%2ADNVHxZtaNDbGgbIKqEtUMQ.gif" alt=""&gt;&lt;/a&gt;Image source: &lt;a href="https://knowyourmeme.com/photos/716245-selena-gomez-crying"&gt;Know Your Meme&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After scouring Stack Overflow and the interwebs (and many tears later), the answer was in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;MDN docs&lt;/a&gt; all along:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QR09gjMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AbSFo0kfUKd7G4Skl96dQ-w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QR09gjMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AbSFo0kfUKd7G4Skl96dQ-w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The users getting 403s were using browsers older than the versions listed above. So this was the fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cross-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/some-route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* some payload */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;same-origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// the fix&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might ask: what about Internet Explorer, your favorite problem child? Well, since &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#Browser_compatibility"&gt;it supports nothing&lt;/a&gt;, the polyfill kicks in with a version of fetch that sets same-origin as the default credentials policy, so no 403s.&lt;/p&gt;

&lt;p&gt;Today I learned.&lt;/p&gt;

&lt;p&gt;📫 &lt;em&gt;Hit me up on&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/suhanwijaya/"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a href="https://twitter.com/suhanw"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>coding</category>
      <category>webdev</category>
      <category>internet</category>
      <category>browsers</category>
    </item>
  </channel>
</rss>
