<?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: William</title>
    <description>The latest articles on Forem by William (@chuloo).</description>
    <link>https://forem.com/chuloo</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%2F314186%2Fe52a7977-7d65-407e-94f5-4dff93d1b70d.jpeg</url>
      <title>Forem: William</title>
      <link>https://forem.com/chuloo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/chuloo"/>
    <language>en</language>
    <item>
      <title>DXC, we engineers hardly know ye</title>
      <dc:creator>William</dc:creator>
      <pubDate>Thu, 27 Oct 2022 11:13:47 +0000</pubDate>
      <link>https://forem.com/chuloo/dxc-we-engineers-hardly-know-ye-3gmh</link>
      <guid>https://forem.com/chuloo/dxc-we-engineers-hardly-know-ye-3gmh</guid>
      <description>&lt;p&gt;“Hey Alex, we have a Black Friday campaign coming up. Gotta update the content on a couple of product pages and create two marketing pages with promo content from the CMS.”&lt;/p&gt;

&lt;p&gt;As a software engineer, you’ve probably been or will soon be Alex. Business practitioners, especially marketers, are insatiable with content requests to fulfill the never-ending demands for updating and enhancing the business strategies at play. &lt;/p&gt;

&lt;p&gt;Those requests can be frustrating for us engineers. Even though the rise of Jamstack, headless, and microservice architectures afford us so-called “software soup” for interacting with valuable tools and technologies, each tool comes with domain-specific, mind-boggling complexities.&lt;/p&gt;

&lt;p&gt;Ultimately, business users and engineers must agree on what to build and how and when to build it. Seamless team dynamics, however, hinges on how efficiently the players can implement the agreed-upon changes.&lt;/p&gt;

&lt;p&gt;Here comes DXC, yet another cutting-edge, next-gen, fire-spitting buzz acronym. We skipped the adjective “blazing-fast” on purpose. &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%2Fpaper-attachments.dropboxusercontent.com%2Fs_E19BD34162CF388930EC411B293A81472BB1E05FB646878331E07741D0414519_1666643430343_image.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%2Fpaper-attachments.dropboxusercontent.com%2Fs_E19BD34162CF388930EC411B293A81472BB1E05FB646878331E07741D0414519_1666643430343_image.png" alt="Current state"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;With &lt;a href="https://uniform.dev/blogs/explaining-dxc-and-its-benefits-to-marketers" rel="noopener noreferrer"&gt;digital experience composition (DXC)&lt;/a&gt;, cross-functional teams can build scalable applications with a focus on what the teams are tasked with. That is, engineers would stick to developing software, and content practitioners would do their job in a content-oriented environment. Other business folks can directly influence all the teams without diminishing overall productivity. &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%2Fpaper-attachments.dropboxusercontent.com%2Fs_E19BD34162CF388930EC411B293A81472BB1E05FB646878331E07741D0414519_1666643482179_image.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%2Fpaper-attachments.dropboxusercontent.com%2Fs_E19BD34162CF388930EC411B293A81472BB1E05FB646878331E07741D0414519_1666643482179_image.png" alt="DXC"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A disclaimer: The DXC-driven scenario has negligible impact on small applications or demos. For scalable applications, DXC makes a huge difference by abstracting content and data from multiple sources into a layer. Business users can then present the result in whatever form or channel they desire, hence the term &lt;strong&gt;composition&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Think of what an easier life you’d have as an engineer if all you had to do was create the presentation layer for structured content, whose schema maintains a specific format. The underlying content comprises data and content from CMSes, headless commerce systems, analytics tools, customer-data platforms, product information management (PIM) systems, search services, etc. &lt;/p&gt;

&lt;p&gt;Simply put, once you’ve defined the page components for the website, other teams can determine the pages to present and their structure—without touching a line of code. For instance, they can identify the text and image sources, the transformations for the images, and the audiences for the various pages. They can personalize content on multiple facets, hold experiments, and update the presentation without help from engineers. Now that’s efficiency. &lt;/p&gt;

&lt;p&gt;Separately, in addition to writing impactful code, engineers have time to explore innovative techniques that promise to optimize the user experience and deliver value faster. Also available is bandwidth to research modern application-rendering models, edge computing, and the techniques for scaling teams with more effective design systems. &lt;/p&gt;

&lt;h2&gt;
  
  
  How does DXC differ from Jamstack and headless technologies?
&lt;/h2&gt;

&lt;p&gt;DXC is built on existing Jamstack and headless-development paradigms to raise cross-team productivity. However, leveraging them at scale risks generating what &lt;a href="https://twitter.com/timbenniks" rel="noopener noreferrer"&gt;Tim Benniks&lt;/a&gt; calls a &lt;a href="https://uniform.dev/blogs/mach-versus-monolithic-suites" rel="noopener noreferrer"&gt;Mach Monolith&lt;/a&gt;. A case in point: Three Jamstack tools in one Next.js-based front end work perfectly fine. However, 10 services later, each communicating with the other, a monolith of headless services emerges. Thus, as much as Jamstack and headless tools are ideal for smaller applications, using them at scale is problem-prone and painstaking.&lt;/p&gt;

&lt;p&gt;DXC is a remarkable workaround: You still use your favorite Jamstack tools, headless services, or even your own home-grown connectors without being locked into any of them. Business users can pick, choose, and swap content any time while engineers focus on building software. &lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;DXC offers relief for engineers, who can bask in the newfound efficiency. Not to mention being able to ensure lateral stability across the application while solidifying the foundation for vertical growth. &lt;/p&gt;

&lt;p&gt;A caveat with DXC solutions is that content orchestration from multiple sources is crucial but not universally available. Here, I unapologetically plug &lt;a href="https://uniform.dev" rel="noopener noreferrer"&gt;Uniform&lt;/a&gt;, where I work, a solution pioneer in this space. For a demo, &lt;a href="https://uniform.app/?signup&amp;amp;utm_campaign=william-blog-post&amp;amp;utm_medium=blo&amp;lt;br&amp;gt;%0Ag" rel="noopener noreferrer"&gt;sign up&lt;/a&gt; for a free account, pick data sources from the suite of integrations, create new components, and watch the orchestration magic unfold.&lt;/p&gt;

&lt;p&gt;“Hey, Sam, how long will it take you to switch our legacy CMS from 2008 to a modern, open-source one?”&lt;/p&gt;

&lt;p&gt;You’re probably not Sam but might be soon, and you need to think about how to handle questions like that.&lt;/p&gt;

&lt;p&gt;For now, Alex is much happier. We are all Alex.&lt;/p&gt;

</description>
      <category>dxc</category>
      <category>jamstack</category>
      <category>webdev</category>
      <category>cms</category>
    </item>
    <item>
      <title>Handling Images in Gatsby with High Performance</title>
      <dc:creator>William</dc:creator>
      <pubDate>Tue, 24 Aug 2021 23:15:31 +0000</pubDate>
      <link>https://forem.com/chuloo/handling-images-in-gatsby-with-high-performance-10ea</link>
      <guid>https://forem.com/chuloo/handling-images-in-gatsby-with-high-performance-10ea</guid>
      <description>&lt;p&gt;&lt;a href="https://cloudinary.com"&gt;Cloudinary&lt;/a&gt; is a cloud-based, end-to-end media-management platform on which you can store, dynamically optimize, and responsively deliver images and videos for both desktop or mobile apps.&lt;br&gt;
The &lt;a href="https://github.com/Chuloo/gatsby-source-cloudinary"&gt;Gatsby-Source-Cloudinary plugin&lt;/a&gt; fetches optimized media assets from a folder on Cloudinary in a Gatsby project. Additionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can declaratively query Cloudinary’s media assets alongside other application data with GraphQL.&lt;/li&gt;
&lt;li&gt;Cloudinary delivers media assets through a content delivery network (CDN), reducing the app- bundle size on build.&lt;/li&gt;
&lt;li&gt;Gatsby-Source-Cloudinary automatically optimizes the quality and format of the media files delivered by Cloudinary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, you have the best of two worlds: high-performance apps along with optimized delivery of media assets.&lt;br&gt;
This tutorial steps you through the process of building a responsive image gallery with Gatsby and images from Cloudinary. Because Gatsby is written in React.js, you must have a working knowledge of JavaScript and React.js.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation of Node.js and Gatsby.js
&lt;/h2&gt;

&lt;p&gt;You need Node.js and its package manager, npm, for this project. To check if they’ve been installed on your system, type the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    node &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the output show no version numbers, go to &lt;a href="https://nodejs.org/"&gt;Nodejs.org&lt;/a&gt; to download and install Node.js, which ships with npm.&lt;br&gt;
Next, install the Gatsby.js CLI tool by typing this command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; gatsby-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creation of Cloudinary Account
&lt;/h2&gt;

&lt;p&gt;To source images from Cloudinary, you must first &lt;a href="https://bit.ly/2v3sy4N"&gt;set up&lt;/a&gt; &lt;a href="https://cloudinary.com/users/register/free"&gt;an account&lt;/a&gt; there. Cloudinary offers a generous, free tier account that’s largely adequate for starter projects and that scales with the project.&lt;br&gt;
Afterwards, do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload the images for the image gallery to a folder in your media library on Cloudinary. Name the folder with a name of your choice, e.g., &lt;code&gt;gallery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Obtain your API key and API secret from your Cloudinary dashboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Creation of New Gatsby Project
&lt;/h2&gt;

&lt;p&gt;Gatsby contains starters that quickly generate new projects with a base setup. To create a new Gatsby project in a folder of your choice with the default starter, type this command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    gatsby new cloudinary-site
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, navigate to the project directory and start a new development server on &lt;code&gt;http://localhost:8000&lt;/code&gt; with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nb"&gt;cd &lt;/span&gt;cloudinary-site &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; gatsby develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because it contains GraphQL, Gatsby simultaneously creates a GraphQL IDE on &lt;code&gt;http://localhost:8000/___graphql&lt;/code&gt;, with which you will build GraphQL queries later.&lt;br&gt;
Now go to &lt;a href="http://localhost:8000/"&gt;http://localhost:8000&lt;/a&gt; to see the new Gatsby project, which looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t1xzNED0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579732344697_image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t1xzNED0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579732344697_image.png" alt="New gatsby project" width="880" height="508"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation of Additional Packages
&lt;/h2&gt;

&lt;p&gt;You need two other packages for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://www.npmjs.com/package/dotenv"&gt;dotenv&lt;/a&gt; module: for loading environment variables from a &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.npmjs.com/package/gatsby-source-cloudinary"&gt;gatsby-source-cloudinary&lt;/a&gt; plugin: for fetching optimized images from Cloudinary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install them with npm by typing this command line:&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="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="nx"&gt;gatsby&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cloudinary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration of gatsby-config.js
&lt;/h2&gt;

&lt;p&gt;You configure all plugins, including those that accompany the default starter, in the &lt;code&gt;gatsby-config.js&lt;/code&gt; file, which resides in the root directory of Gatsby projects. Do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Import the &lt;code&gt;dotenv&lt;/code&gt; file you installed earlier to the &lt;code&gt;gatsby-confi.js&lt;/code&gt; file and add the &lt;code&gt;gatsby-source-cloudinary&lt;/code&gt; plugin with this code:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&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;plugins&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="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-source-cloudinary`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;cloudName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_CLOUD_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_API_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;resourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`image`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-source-cloudinary/`&lt;/span&gt; 
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;gatsby-source-cloudinary&lt;/code&gt; takes these options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cloudName&lt;/code&gt;, &lt;code&gt;apiKey&lt;/code&gt; , and &lt;code&gt;apiSecret&lt;/code&gt;. These are credentials from your Cloudinary console, stored as three separate environment variables for security.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resourceType&lt;/code&gt; This is the resource type of the media assets: either an image or a video.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prefix&lt;/code&gt; This is the folder (in your Cloudinary account) in which the files reside. In the example above, I named this folder &lt;code&gt;gatsby-source-cloudinary&lt;/code&gt;. Assign a name of your choice.
Other optional options are &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, and &lt;code&gt;maxResult&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;In the root of your project, create an environment file called &lt;code&gt;.env&lt;/code&gt; to which to add your Cloudinary credentials and their values, like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nv"&gt;CLOUDINARY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxxxxxxxxxxxxx
    &lt;span class="nv"&gt;CLOUDINARY_API_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxxxxxxxxxxxxxxxxxxx
    &lt;span class="nv"&gt;CLOUDINARY_CLOUD_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The `dotenv` package exposes those environment variables in the project.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Restart the Gatsby development server to see the plugin in action, as in this example:
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p1ya9v10--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579734262094_image.png" alt="Installation progress in console" width="880" height="171"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;info&lt;/code&gt; log, which displays the CloudinaryMedia nodes. Those images are ready to be queried in Gatsby components.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creation of Image Gallery
&lt;/h2&gt;

&lt;p&gt;To create the image gallery:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the &lt;code&gt;src/components&lt;/code&gt; folder, create a component file called &lt;code&gt;ImageGallery.js&lt;/code&gt; and add the React functional component to the file, as follows:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="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="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./gallery.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;useStaticQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gatsby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ImageGallery&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStaticQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`query CloudinaryImage {
                allCloudinaryMedia {
                  edges {
                    node {
                      secure_url
                    }
                  }
                }
              }`&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;clImages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allCloudinaryMedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"image-grid"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;clImages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"image-item"&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-cl`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secure_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no alt :(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
                      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;ImageGallery&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, you query all the Cloudinary images sourced into the &lt;code&gt;CloudinaryMedia&lt;/code&gt; nodes with the &lt;code&gt;useStaticQuery&lt;/code&gt; hook. In turn, you map through those image URLs to create a gallery with the component.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a file called &lt;code&gt;./gallery.css&lt;/code&gt; in &lt;code&gt;src/components&lt;/code&gt; for styling the component. Add the CSS styles to the file, as follows:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;    &lt;span class="nc"&gt;.image-grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;grid-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="py"&gt;grid-auto-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nc"&gt;.image-grid&lt;/span&gt; &lt;span class="nc"&gt;.image-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;n&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="py"&gt;grid-column-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nc"&gt;.image-grid&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;object-fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The above styling renders your image gallery into a beautiful, responsive masonry grid.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Replace the existing content of the &lt;code&gt;index.js&lt;/code&gt; file in the &lt;code&gt;src/pages&lt;/code&gt; folder with the newly created &lt;code&gt;ImageGallery&lt;/code&gt; component, as follows:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SEO&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/seo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ImageGallery&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/ImageGallery&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;IndexPage&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SEO&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Image Gallery&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Here's a Gatsby site with optimized images in a masonry grid, served from &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https:cloudinary.com"&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Cloudinary&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`1.45rem`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ImageGallery&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;IndexPage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gatsby automatically creates dynamic routes for single pages in the  `src/pages` folder, with `index.js` being the root or home page.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Optional&lt;/strong&gt;. Feel like tweaking the styles a bit? In the &lt;code&gt;src/components/header.js&lt;/code&gt; file, change the &lt;code&gt;background&lt;/code&gt; style property of the &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; element to &lt;code&gt;#002954&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You might also like to rewrite the site title, which is pulled from the site metadata specified in &lt;code&gt;gatsby-config.js&lt;/code&gt;. Update the &lt;code&gt;title&lt;/code&gt; property of &lt;code&gt;siteMetadata&lt;/code&gt; to Gatsby-Cloudinary Image Gallery.&lt;/p&gt;

&lt;p&gt;Now restart the development server and have a look at the updated page. Here’s an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7vKFJgoC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579735865260_gsc-sample.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7vKFJgoC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579735865260_gsc-sample.gif" alt="Image gallery from Cloudinary" width="640" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, create a deployable, optimized build by typing this command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    gatsby build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment to Netlify
&lt;/h2&gt;

&lt;p&gt;To deploy this JAMstack app to &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt; with a prebuilt continuous integration and continuous delivery (CI/CD) pipeline, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push your code to a remote repository, such as GitHub or Bitbucket.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.netlify.com/signup"&gt;Create a Netlify account&lt;/a&gt; and log in.&lt;/li&gt;
&lt;li&gt;Create a new project from your deployed repository on Netlify.&lt;/li&gt;
&lt;li&gt;Type the build command and build directory in the text fields, in this case &lt;code&gt;gatsby build&lt;/code&gt; and &lt;code&gt;public&lt;/code&gt;, respectively. In most cases, Netlify detects the technology and auto-populates those fields.&lt;/li&gt;
&lt;li&gt;Add the environment variables to the environment variables settings on Netlify. Omitting this step will cause the deployment to fail.&lt;/li&gt;
&lt;li&gt;Run the deployment and voila! Your image gallery has taken shape.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the &lt;a href="https://gsc-sample.netlify.com/"&gt;deployed version&lt;/a&gt; of this project.&lt;br&gt;
And here’s the lighthouse audit of the deployed website, which showcases the power of Gatsby and Cloudinary with eight high-resolution images delivered on the page you just created:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--31S8Jf6i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579736874654_image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--31S8Jf6i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_F2DB697C20DB2900E952897A6582F157DAE4391AB0ADA1EBD0D8E2F67307CC1F_1579736874654_image.png" alt="Lighthouse performance scores" width="880" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the complete code, see its &lt;a href="https://github.com/Chuloo/gatsby-source-cloudinary-example"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Now that you’ve learned how to build an optimized and responsive image masonry with the Gatsby-Source-Cloudinary plugin on Cloudinary, you can apply the process to other websites and apps on the JAMstack architecture.&lt;br&gt;
Also, do check out the &lt;a href="https://www.npmjs.com/package/gatsby-transformer-cloudinary"&gt;Gatsby-Transformer-Cloudinary plugin&lt;/a&gt;, with which you can upload media assets to Cloudinary and create file nodes off them, ready for use in the robust &lt;code&gt;gatsby-image&lt;/code&gt; component in React. Have fun!&lt;/p&gt;

</description>
      <category>react</category>
      <category>gatsby</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>11 Tools to Use as a Technical Product Manager</title>
      <dc:creator>William</dc:creator>
      <pubDate>Thu, 25 Mar 2021 21:00:22 +0000</pubDate>
      <link>https://forem.com/chuloo/11-tools-to-use-as-a-technical-product-manager-126b</link>
      <guid>https://forem.com/chuloo/11-tools-to-use-as-a-technical-product-manager-126b</guid>
      <description>&lt;p&gt;As a Technical Product Manager, one of the hurdles I had to pass was setting up and working with various tools to help speed up my work and boost my productivity.&lt;/p&gt;

&lt;p&gt;Multiple product management tools abound on the internet. They mostly proffer the same solution of "defining actionable solution requirements and reporting outcomes within a certain timeline." Each tool has its strength, and just as the product management discipline doesn't follow one-size-fits-all, different combinations of tools are required to achieve specific desired outcomes.&lt;/p&gt;

&lt;p&gt;I hope I don't say the word 'outcomes' too much ;)&lt;/p&gt;

&lt;p&gt;"A good workman is known by his tools". Below is a list of eleven of mine in no particular order, and I hope I'm good. This list consists of tools used in strategy definition, product design, reporting, presentation, communication, and analytics.&lt;/p&gt;

&lt;p&gt;This list is opinionated. If you find the tools useful, that's great. Else, could you not hold it against me?&lt;/p&gt;

&lt;h4&gt;
  
  
  Product Board
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.productboard.com/"&gt;Productboard&lt;/a&gt; is one of my favorites. I use it to proritize product features against strategic intents/outcomes and development efforts. This is where strategic and operational product management happens. A cool part of Productboard is Portals. With portals, we prioritize product features with feedback from multiple data points, which users can send in via Slack, email, or any of the other data sources.&lt;/p&gt;

&lt;p&gt;As a startup, we use multiple prioritization methods. Objectives exist in Productboard to handle prioritization with a sort of MoSCoW approach. Also, with Productboard, you can make a custom prioritization system using Drivers and Scores. Drivers are key metrics that we define and set the impact of the feature on the driver. A group of drivers with individual weights makes up a Score. I'd mostly sort features according to a score, powered by a group of drivers.&lt;/p&gt;

&lt;p&gt;With Productboard, I get a holistic view of the roadmap (which I split into quarterly buckets). Having this view on the board showing Drivers, Objectives, and Scores quickly explains WHY and WHEN for any feature.&lt;/p&gt;

&lt;h4&gt;
  
  
  Trello
&lt;/h4&gt;

&lt;p&gt;Good ol&lt;a href="https://trello.com/"&gt;'Trello&lt;/a&gt; for product management had to make the cut. Trello is my favorite tool to manage our Kanban boards and task delegation for several reasons. This includes its clean interface and rich integrations.&lt;/p&gt;

&lt;p&gt;With a small team shipping software, our sprint cycles are weekly, and releases are sometimes daily. A tool to manage this tactical product management process should help us do this seamlessly by defining requirements, acceptance tests, delivery dates, and assigning the task. Trello did just that.&lt;/p&gt;

&lt;p&gt;With integration to GitHub, we're able to tie pull requests and issues to Trello cards. An excellent add-on for Trello is the &lt;a href="https://trello.com/power-ups/59c3d177178a761767b49278/card-numbers-by-reenhanced"&gt;Card numbers&lt;/a&gt; integration that adds the card number to a card. A card number makes for easy referencing in sprint plannings, standup, and sprint retrospectives.&lt;/p&gt;

&lt;p&gt;If you exceed your power-up limit for Trello, you can explore &lt;a href="https://chrome.google.com/webstore/detail/card-numbers-for-trello/ddadhlcejiholmdiihbdcfoapdfkhicn/related"&gt;this chrome extension to add card numbers to Trello cards.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Toggl Plan
&lt;/h4&gt;

&lt;p&gt;Product managers can create roadmaps on Productboard. However, the experience with creating a Gantt chart on a calendar isn't as optimal (or maybe I don't find it aesthetically pleasing). I use &lt;a href="https://toggl.com/plan/"&gt;Toggl plan&lt;/a&gt; to represent the roadmap stages on a calendar. Toggl Plan is visually attractive and effortless to drag and drop the timelines. A useful feature is also the ability to export a plan with various timelines and even share a link to a project so all stakeholders can see current progress and what's upcoming.&lt;/p&gt;

&lt;p&gt;Traditionally, I would do something similar on Google sheets and spend a lot of time with stylings and updating progress.&lt;/p&gt;

&lt;p&gt;Toggl has a free tier that doesn't include a lot of features in the paid plan. However, if you need a visual representation of your project/product roadmap on a calendar, then the free plan is enough.&lt;/p&gt;

&lt;h4&gt;
  
  
  Google Suite
&lt;/h4&gt;

&lt;p&gt;Google Sheets, Google Docs, and Google Slides get the nod for creating spreadsheets, documents, and presentations, respectively. A significant win for these is the ability to collaborate on documents and export to any format.&lt;/p&gt;

&lt;p&gt;As a technical product manager in e-commerce, Google sheets sometimes serves as an unlikely data source in development. Stakeholders in business teams are usually comfortable sharing data in sheets. This sheet is converted from a CSV export to JSON format and used in software development. It saves everyone time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Notion
&lt;/h4&gt;

&lt;p&gt;Creating processes and documenting them is a big part of building a successful engineering and product team. We use &lt;a href="https://www.notion.so/"&gt;Notion&lt;/a&gt; to write all developed processes, create wikis and guides, and onboard new team members.&lt;/p&gt;

&lt;p&gt;It feels better suited for a knowledge base, and we use it as such.&lt;/p&gt;

&lt;h4&gt;
  
  
  GitHub
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; is a platform to manage software development. As a lean distributed team, everything in development happens here, and as a Technical Product Manager, understanding the different parts cannot be overemphasized. You probably don't need to know the inner technical workings and features; however, making commits, pulling, pushing, making pull requests, and issues are some fundamentals you need to know.&lt;/p&gt;

&lt;p&gt;GitHub enables efficient collaboration and automation between team members both in development and deployment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Excalidraw
&lt;/h4&gt;

&lt;p&gt;Design-focused Product managers would probably be skewed to using Figma and Sketch tools to make design mocks and rough sketches. As a technical product manager with little experience creating user interface designs, I found &lt;a href="https://excalidraw.com/"&gt;Excalidraw&lt;/a&gt; a handy tool to make sketches and rough prototypes of ideas quickly.&lt;/p&gt;

&lt;p&gt;These go from screens to pages and charts. Also, a big win with Excalidraw is the gentle learning curve. Unlike most design tools with confusing toolbars and 16 menus (just kidding), Excalidraw keeps it pretty minimal.&lt;/p&gt;

&lt;p&gt;Figma still deserves mention for collaborative prototyping if product design is among your strengths.&lt;/p&gt;

&lt;h4&gt;
  
  
  Draw.io
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://draw.io/"&gt;Draw.io&lt;/a&gt; is one tool I find super useful when communicating ideas to stakeholders. Draw.io allows you to create flowcharts and diagrams with multiple available elements. With draw.io, I'm able to make user and process flow diagrams in minutes.&lt;/p&gt;

&lt;p&gt;With Draw.io, you can also make Entity Relationship Diagrams for databases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Google Analytics
&lt;/h4&gt;

&lt;p&gt;Feedback collection on product usage is at the heart of product development. &lt;a href="https://hackmamba.io/blog/2021/03/11-tools-to-use-as-a-technical-product-manager/"&gt;Google Analytics&lt;/a&gt; provides data on multiple telemetries when appropriately integrated for free. I use it on websites to analyze automatically-collected data and also analyze custom data triggered through events.&lt;/p&gt;

&lt;p&gt;With Google Analytics, we can analyze user acquisition, retention, conversion, anonymous audience information, and user behavior. Other features include creating paths and user funnels using custom events.&lt;/p&gt;

&lt;p&gt;While Google Analytics gets some criticism due to privacy concerns, It gets a nod for the feature set at no cost.&lt;/p&gt;

&lt;h4&gt;
  
  
  Slack
&lt;/h4&gt;

&lt;p&gt;The online office. &lt;a href="https://slack.com/"&gt;Slack&lt;/a&gt; enables team communications in channels, direct messages, and group messages. Slack is a useful tool for teams to work effectively, featuring an excellent interface and rich text editor to communicate efficiently.&lt;/p&gt;

&lt;p&gt;A strength of Slack is in the ability to extend its capabilities with integrations. For us, we use the following base integrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Google Suite&lt;/li&gt;
&lt;li&gt;Trello&lt;/li&gt;
&lt;li&gt;Productboard&lt;/li&gt;
&lt;li&gt;Uptime Robot (to track server uptime)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice how most of the tools already listed have Slack integrations always to keep everyone in the loop? That's the beauty of Slack. There are hundreds of Slack integrations for your team or product use-case.&lt;/p&gt;

&lt;p&gt;Yea, we don't use the call feature on Slack too :)&lt;/p&gt;

&lt;h4&gt;
  
  
  Zoom
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://zoom.us/"&gt;Zoom&lt;/a&gt; gets an honorable mention for being there for us when we needed to make calls with low internet bandwidth. We use Zoom for video communications as a distributed team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this post, I discussed 11 tools I use as a Technical Product Manager to develop and ship technology products. As this is an opinionated post, your choice may differ, or you may find that a tool eliminates the need for another. Whichever helps you do your most impactful work is the right tool.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2021/03/11-tools-to-use-as-a-technical-product-manager/"&gt;Hackmamba&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>management</category>
      <category>programming</category>
    </item>
    <item>
      <title>Explaining Web Apps State Management like ABC</title>
      <dc:creator>William</dc:creator>
      <pubDate>Fri, 12 Mar 2021 08:35:33 +0000</pubDate>
      <link>https://forem.com/chuloo/explaining-web-apps-state-management-like-abc-513o</link>
      <guid>https://forem.com/chuloo/explaining-web-apps-state-management-like-abc-513o</guid>
      <description>&lt;p&gt;In building out web applications using React.js, I've had to manage both component and application state. While the component state is managed with built-in methods, the application state is managed using tools like Redux.&lt;/p&gt;

&lt;p&gt;How does Redux work? The documentation talks about actions, constants, and reducers. Which I and much everyone else uses. However, I'd struggled to internalize this concept and how it's all put together.&lt;/p&gt;

&lt;p&gt;I recently asked &lt;a href="https://twitter.com/meabed" rel="noopener noreferrer"&gt;Meabed&lt;/a&gt; to explain to me in his terms, how state management works and he did just that. I'm writing to you to explain using an HTML file and the browser &lt;code&gt;window&lt;/code&gt; object, how state management tools possibly like Redux work, with stores, constants, actions, subscriptions &amp;amp; updates, and reducers.&lt;/p&gt;

&lt;p&gt;All these will be done on Codesandbox and you can find the final sandbox &lt;a href="https://codesandbox.io/s/nostalgic-bardeen-pmyur?file=/index.html" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Create the HTML file
&lt;/h4&gt;

&lt;p&gt;I created a simple index.html file and opened it in the browser (no bundler required). The file contains the following:&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="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Static Template&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Building out state from Scratch using a counter and input&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Create static HTML elements
&lt;/h4&gt;

&lt;p&gt;We require 2 script tags, one before the &lt;code&gt;body&lt;/code&gt; element to load Javascript before the document loads, and another after the document is loaded. The first will manage the state logic and the second will update the page. Also, we will demonstrate the state update using a counter with 2 buttons and an input field. With these we have:&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="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Static Template&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle State management&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Building out state from Scratch using a counter and input&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter_data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{counter} - {name}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"decrement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;decrement&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Update DOM&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We created a simple HTML document with 2 buttons, a counter - name display, and an input element. The goal is to increment and decrement a counter value (which we will assign shortly), and update the &lt;code&gt;{name}&lt;/code&gt; value with whatever is entered in the input.&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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1600686429%2FScreen_Shot_2020-09-21_at_3.06.01_PM_rllz7l.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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1600686429%2FScreen_Shot_2020-09-21_at_3.06.01_PM_rllz7l.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may wonder why we have to go through this long process to handle increments and decrements. You are right. For small applications like counters, handling an application state is trivial, as a single JS file is sufficient. However, in larger projects, there is a need to organize and manage the flow of data throughout the components.&lt;/p&gt;

&lt;h4&gt;
  
  
  How state management works (theoretically)
&lt;/h4&gt;

&lt;p&gt;In clear steps, we will handle the state in this app with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a data store in the window object that is accessible everywhere in the browser&lt;/li&gt;
&lt;li&gt;Create a function to update the DOM (the fancy term is 'render engine')&lt;/li&gt;
&lt;li&gt;Create functions to update the store data (these are actions)&lt;/li&gt;
&lt;li&gt;Define a new store data in the function to update the store (this is a reducer)&lt;/li&gt;
&lt;li&gt;Create a global function that receives function calls to update the store along with any provided data. It updates the store and re-renders the webpage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technologies like React and Redux work to optimize this process and enhance the development experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating a data store
&lt;/h4&gt;

&lt;p&gt;In the opening script element, we will create an object as a data store in the &lt;code&gt;window&lt;/code&gt; object.&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;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle State management&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;"&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;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Building out state from Scratch using a counter and input&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter_data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{counter} - {name}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"decrement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;decrement&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Update DOM&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
[...] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Create a render function for the DOM
&lt;/h4&gt;

&lt;p&gt;A quick render function will replace specific portions of an identified DOM node value with variables from the store. In the second script tag before the closing body tag, we have:&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;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle State management&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;"&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;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Building out state from Scratch using a counter and input&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter_data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{counter} - {name}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"decrement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;decrement&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Update DOM&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalData&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter_data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Store original state before state changes, required for rerender&lt;/span&gt;

      &lt;span class="c1"&gt;// Render function&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderData&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="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter_data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalData&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{counter}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{name}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;renderData&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;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We created a render function with a basic template engine (hell yeah!) which replaces &lt;code&gt;{counter}&lt;/code&gt; and &lt;code&gt;{name}&lt;/code&gt; with data from the global store. With the data from the store, the page looks like:&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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1600686826%2FScreen_Shot_2020-09-21_at_3.13.26_PM_tikuak.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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1600686826%2FScreen_Shot_2020-09-21_at_3.13.26_PM_tikuak.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Create functions(actions) and reducers to modify data
&lt;/h4&gt;

&lt;p&gt;To increment, decrement, and update the page, we will create functions that update the store data. In the first script element, we create 3 functions having:&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="c1"&gt;// Handle State management&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="c1"&gt;// Create functions&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// reducer&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newName&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;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have &lt;code&gt;increment&lt;/code&gt;, &lt;code&gt;decrement&lt;/code&gt; and &lt;code&gt;setName&lt;/code&gt; functions to increment, decrement, and update the name data respectively. Also, for now, the expression in the actions is just to update the store data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Call actions on button click and input change
&lt;/h4&gt;

&lt;p&gt;The next step is to call the actions on button click and input change. We update the buttons and input then rerender the element for each action completion. We now have:&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="c1"&gt;// Handle State management&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="c1"&gt;// Create functions&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// reducer&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;renderData&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="nf"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;renderData&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="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;renderData&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;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Building out state from Scratch using a counter and input&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"increment()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter_data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{counter} - {name}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"decrement"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"decrement()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;decrement&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your email"&lt;/span&gt; &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;"setName(this.value)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this time, the counter works as well as the input object.&lt;/p&gt;

&lt;p&gt;Immutability is a core part of how tools like Redux and React work, with those, the state is not mutated as we do at the moment. Here, we re-render the elements for every action, this has a huge performance overhead when managing a large application. Also with state-controlled from multiple app points, there is multi-directional data flow which could lead to data inconsistencies in an app.&lt;/p&gt;

&lt;p&gt;Following these, state data should not be mutated, however, a new version of the state is created. This way, efficient render engines like in React.js know from comparing the previous state object and the new state object, when to render, and what portion of the app to rerender. Subsequently, you can look up "Shallow compare" and "Deep equality" of objects in JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create a sample redux store
&lt;/h4&gt;

&lt;p&gt;To achieve immutability, we will create a store which has a function that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dispatches an action&lt;/li&gt;
&lt;li&gt;Takes a data returned in the action (reducer)&lt;/li&gt;
&lt;li&gt;Merges it with the store data (root reducer)
In the opening script element we add the &lt;code&gt;window.reduxStore&lt;/code&gt; object with:
&lt;/li&gt;
&lt;/ul&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="c1"&gt;// Handle State management&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="c1"&gt;// redux store with dispatch&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduxStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&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;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="nf"&gt;renderData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the dispatch method, we receive &lt;code&gt;action&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; as parameters. Each action function to be 'dispatched' has a unique name, and when used in the dispatch function, it is used to call the action and assign it to a new variable called &lt;code&gt;newData&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The data sent in the dispatch function is passed to the action which is in turn used in the reducer. The result is spread along with the existing store data into new value for the store, rather than mutating/modifying the store itself.&lt;/p&gt;

&lt;p&gt;With the re-rendering out of the way, we can clean up the action functions to:&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="c1"&gt;// Handle State management&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduxStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&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;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="nf"&gt;renderData&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="c1"&gt;// Create functions&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// reducer&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="nf"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="nf"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newName&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;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, update the buttons and input to dispatch the actions while passing only the action name, which seems like a &lt;strong&gt;constant&lt;/strong&gt;, sound familiar from react-redux? hehe.&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;h1&amp;gt;&lt;/span&gt;Building out state from Scratch using a counter and input&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"window.reduxStore.dispatch('increment')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Increment
    &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"counter_data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{counter} - {name}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"decrement"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"window.reduxStore.dispatch('decrement')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      decrement
    &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
      &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your email"&lt;/span&gt;
      &lt;span class="na"&gt;onchange=&lt;/span&gt;&lt;span class="s"&gt;"window.reduxStore.dispatch('setName', this.value)"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we have the data flowing from application state to components and state management completed using the &lt;code&gt;window&lt;/code&gt; object as a store. The buttons manipulate the resulting number on increment or decrement, whereas the input element updates the name field when you click out of the form input after a form entry.&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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1600721192%2Fstate_giphy_am0zbl.gif" 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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1600721192%2Fstate_giphy_am0zbl.gif" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Recap
&lt;/h4&gt;

&lt;p&gt;We have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A button triggers a defined action function&lt;/li&gt;
&lt;li&gt;The action returns a reducer&lt;/li&gt;
&lt;li&gt;A new store is created with the new state data as the previous store data is immutable&lt;/li&gt;
&lt;li&gt;The DOM elements are re-rendered to reflect the updated state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools like &lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt; and &lt;a href="https://react-redux.js.org/" rel="noopener noreferrer"&gt;React-redux&lt;/a&gt; work to optimize every step of this process by having abstracted and clearly defined,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actions&lt;/li&gt;
&lt;li&gt;Constant&lt;/li&gt;
&lt;li&gt;Reducers&lt;/li&gt;
&lt;li&gt;Subscribers&lt;/li&gt;
&lt;li&gt;Rendering, as well as a host of optimization techniques.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the complete code sandbox to this &lt;a href="https://codesandbox.io/s/nostalgic-bardeen-pmyur?file=/index.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this gives you a better understanding of how state management works. Also, this is just the base of the concept and you can read through multiple state management libraries for more insights.&lt;/p&gt;

&lt;p&gt;Till next time.&lt;/p&gt;

&lt;p&gt;William.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2020/09/explaining-web-apps-state-management-like-abc/" rel="noopener noreferrer"&gt;Hackmamba.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Dynamic JavaScript Object Keys</title>
      <dc:creator>William</dc:creator>
      <pubDate>Tue, 09 Mar 2021 06:32:52 +0000</pubDate>
      <link>https://forem.com/chuloo/dynamic-javascript-object-keys-5hbc</link>
      <guid>https://forem.com/chuloo/dynamic-javascript-object-keys-5hbc</guid>
      <description>&lt;p&gt;Excuse the barrage of doggos in the banner image. I searched for a stock image on &lt;a href="https://unsplash.com/"&gt;unsplash&lt;/a&gt; for "Puppies with different colors being named by their mom". I do search in the tackiest of ways 😃&lt;/p&gt;

&lt;p&gt;I hope they brighten your time also.&lt;/p&gt;

&lt;p&gt;Recently, I found a 'funny' JS syntax when reviewing a pull request by &lt;a href="https://twitter.com/6igo_cross"&gt;Sigo&lt;/a&gt;, a colleague. I hadn't used it previously. It 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataFromAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;'&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;existingObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&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;dataFromAPI&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Output {age: 25, name: "John"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amazing!&lt;/p&gt;

&lt;p&gt;I looked up variables in object keys and decided to share it with you.&lt;/p&gt;

&lt;h4&gt;
  
  
  Keys and Values in Objects
&lt;/h4&gt;

&lt;p&gt;In JavaScript, object keys and values are created in numerous ways either in object literals during initialization, or assignment using dot or bracket notation.&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;// Creating an object literal with keys and values&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Adding a new key - bracket notation&lt;/span&gt;
&lt;span class="nx"&gt;newObject&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Peru&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Adding a new key - Dot notation&lt;/span&gt;
&lt;span class="nx"&gt;newObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.95m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Output {age: 24, height: "1.95m", location: "peru", name: "Jane"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty much standard stuff. For values of keys, we are able to assign results from complex computation operations as a value. For keys, we can do something similar and even run the computation in the key.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dynamic Object Keys
&lt;/h4&gt;

&lt;p&gt;A way to handle dynamic keys in objects prior to ES6 is to do something like:&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;newObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&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;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;newObject&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nicaragua&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Output {age: "24", location: "Nicaragua", name: "Jane"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A shorthand form introduced in ES6 using brackets lets us assign the variable in the object literal directly 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;"&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;newObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nicaragua&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Output {age: "24", location: "Nicaragua", name: "Jane"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this shorthand form is proffering cleaner code, this scenario applies in multiple cases, where existing data (object) is augmented with data from a different source with a dynamic key.&lt;/p&gt;

&lt;p&gt;Moving on to computed keys, the value of object keys can be computed directly in the object literal using the same bracket notation in the literal.&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;const&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lottery&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;didUserWin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;newObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;didUserWin&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Winner&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;Loser&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="s2"&gt;Assign any value or data here&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Output {age: "24", lotteryWinner: "Assign any value or data here", name: "Doug"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This illustration also shows the use of conditions in the form of ternary operators.&lt;/p&gt;

&lt;p&gt;This post is mainly to show the dynamism of both Object keys and values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/iChuloo"&gt;Let me know&lt;/a&gt; if you have any feedback using this.&lt;/p&gt;

&lt;p&gt;Here's to becoming better 🥂&lt;/p&gt;

&lt;p&gt;William.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2020/11/dynamic-javascript-object-keys/"&gt;Hackmamba&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tech</category>
      <category>jsx</category>
    </item>
    <item>
      <title>Top 5 Rich-Text React Components</title>
      <dc:creator>William</dc:creator>
      <pubDate>Wed, 03 Mar 2021 18:07:28 +0000</pubDate>
      <link>https://forem.com/sanity-io/top-5-rich-text-react-components-5al7</link>
      <guid>https://forem.com/sanity-io/top-5-rich-text-react-components-5al7</guid>
      <description>&lt;h1&gt;
  
  
  Top 5 Rich-Text React Components
&lt;/h1&gt;

&lt;p&gt;Content is at the heart of web interfaces. Rich text makes up the crust of creating text content with differently formatted parts. &lt;br&gt;
In this article, we will illustrate five rich text components for creating content in React applications. &lt;/p&gt;

&lt;p&gt;We will also look at the pros and cons of each component. &lt;/p&gt;

&lt;p&gt;Lastly, we will discuss the future of the dynamic presentation of content using Portable Text and how to use Portable Text from &lt;a href="https://www.sanity.io/studio" rel="noopener noreferrer"&gt;Sanity Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rich text is used in various forms of presentations on the web, including blog posts, articles, listings, and more robust interfaces like e-commerce product descriptions and social media. &lt;/p&gt;

&lt;p&gt;Below are 5 top rich text components for React.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draft.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://draftjs.org/" rel="noopener noreferrer"&gt;Draft.js&lt;/a&gt; is a robust, extensible, and customizable React.js framework for building rich text editors. It provides the building blocks for building rich text inputs with an immutable approach to managing data.&lt;/p&gt;

&lt;p&gt;Draft.js follows the same paradigm as controlled components in React and provides an &lt;code&gt;Editor&lt;/code&gt; component that renders a rich text input.&lt;br&gt;
Draft.js exposes an &lt;code&gt;EditorState&lt;/code&gt; API to handle/store state updates in the &lt;code&gt;Editor&lt;/code&gt; component. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
Draft-js requires React and React-DOM. We install them using npm or yarn with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install &lt;/span&gt;draft-js react react-dom
    yarn add draft-js react react-dom


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Editor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EditorState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;draft-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RichtextEditor&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;editorState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEditorState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;EditorState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="na"&gt;editorState&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;editorState&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setEditorState&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;onChange&lt;/code&gt; handler overwrites the &lt;code&gt;editorState&lt;/code&gt; data with the new data in the editor. &lt;code&gt;editorState&lt;/code&gt; holds an &lt;a href="https://immutable-js.github.io/" rel="noopener noreferrer"&gt;&lt;em&gt;immutable Record&lt;/em&gt;&lt;/a&gt; with all changes and events in the editor and is simply a &lt;em&gt;snapshot&lt;/em&gt; of its state.&lt;/p&gt;

&lt;p&gt;Draft.js provides props to manage various configurations, including editor styling on event triggers and block styling for singular rich text entities like headers and blockquotes.&lt;/p&gt;

&lt;p&gt;With the content created in the editor, we want to convert this to HTML, which we can display on a page. There are libraries to handle the conversion of this data, including &lt;em&gt;draft-convert&lt;/em&gt; and &lt;em&gt;draftjs-to-html&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Robust and customizable data on a document level and lower level into blocks of various text elements&lt;/li&gt;
&lt;li&gt;Uses immutable-js to manage performant state updates&lt;/li&gt;
&lt;li&gt;Supports custom controls&lt;/li&gt;
&lt;li&gt;Ships text directions for RTL languages and spell-checker&lt;/li&gt;
&lt;li&gt;EditorState contains undo/redo stacks and any other action done on the editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires setup from scratch, plus controls to set up a full-fledged editor&lt;/li&gt;
&lt;li&gt;Requires a parser installed to render entered markup
## React-Draft- WYSIWYG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://jpuri.github.io/react-draft-wysiwyg/#/" rel="noopener noreferrer"&gt;React-draft-wysiwyg&lt;/a&gt; is an editor built on Draft.js. Suppose you don’t want the hassles of building your own rich text editor UI from scratch. In that case, react-draft offers a fully fitted editor with options to customize the editor even further. &lt;/p&gt;

&lt;p&gt;React-draft also provides the ability to use the editor as a controlled or uncontrolled component. React-draft provides the option to customize the toolbar options and add custom react components to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
React-draft depends on Draft.js, React, and react-dom. We install React-draft using npm or yarn with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install &lt;/span&gt;react-draft-wysiwyg draft-js react react-dom
    yarn add react-draft-wysiwyg draft-js react react-dom


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br&gt;
With react-draft, &lt;code&gt;EditorState&lt;/code&gt;, an &lt;a href="https://immutable-js.github.io/" rel="noopener noreferrer"&gt;immutable Record&lt;/a&gt; of the editor’s state, is imported from draft-js and &lt;code&gt;Editor&lt;/code&gt; from &lt;code&gt;react-draft-wysiwyg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s usage on a React page:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Editor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-draft-wysiwyg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EditorState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;draft-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-draft-wysiwyg/dist/react-draft-wysiwyg.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;editorState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEditorState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;EditorState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="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;editorState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;editorState&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;React Editors&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Start editing to see some magic happen!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;400px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt;
              &lt;span class="na"&gt;editorState&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;editorState&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onEditorStateChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setEditorState&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;The resulting editor looks like this:&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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610024395682_image.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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610024395682_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above code snippet shows the usage of React-Draft-WYSIWYG as a controlled component. In an uncontrolled behavior, the &lt;code&gt;initialEditorState&lt;/code&gt; prop is used instead of the &lt;code&gt;editorState&lt;/code&gt; prop in &lt;code&gt;&amp;lt;Editor/&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides ready-made UI out of the box&lt;/li&gt;
&lt;li&gt;Allows for UI enhancements and customizations, including emoji support&lt;/li&gt;
&lt;li&gt;Accepts props of CSS class names for speedy editor styling&lt;/li&gt;
&lt;li&gt;Easily set up hashtags and mentions with suggestions from a dataset&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires a parser to convert &lt;code&gt;EditorState&lt;/code&gt; to HTML or any other markup.&lt;/li&gt;
&lt;li&gt;Parsers for draft-js to HTML or any additional markup could be inadequate in handling the different block/element types.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  React Quill
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://quilljs.com/" rel="noopener noreferrer"&gt;Quill.js&lt;/a&gt; is a fast and lightweight rich text editor built with cross-platform and cross-browser support in mind. &lt;br&gt;
Its strength also lies in its extensibility and configurability using themes. &lt;br&gt;
&lt;a href="https://github.com/zenoamaro/react-quill" rel="noopener noreferrer"&gt;React-Quill&lt;/a&gt; is a Quill component for React with support for TypeScript. React-Quill ships with a full-featured editor with the option to customize the toolbars and set up themes. &lt;/p&gt;

&lt;p&gt;React-Quill is seamless to integrate. React-quill touts a hybrid input of controlled and uncontrolled behavior, using the component's &lt;code&gt;value&lt;/code&gt; prop bound to its state. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;React-Quill also features an uncontrolled mode that uses &lt;code&gt;defaultValue&lt;/code&gt; to instantiate the editor data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A theme specification and a function passed to the &lt;code&gt;onChange&lt;/code&gt; prop of the component are only required to render the editor and handle data input. &lt;br&gt;
React-Quill outputs HTML and can be used in JSX elements with &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
React-quill is installed via npm or yarn with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install &lt;/span&gt;react-quill
    yarn add react-quill


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br&gt;
Import the React-quill component along with the theme required. The default theme &lt;em&gt;Snow&lt;/em&gt; is used when a theme is not specified.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactQuill&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-quill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-quill/dist/quill.snow.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;convertedText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setConvertedText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some default content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactQuill&lt;/span&gt;
            &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'snow'&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;convertedText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setConvertedText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;minHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;300px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows complete toolbar customization with HTML &amp;amp; JSX elements support&lt;/li&gt;
&lt;li&gt;Ease of setup and use&lt;/li&gt;
&lt;li&gt;It outputs HTML, so it serves simpler use cases like blog posts and content presentation layers with precise data requirements.&lt;/li&gt;
&lt;li&gt;Theming support for preset editor styling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited customization of content blocks&lt;/li&gt;
&lt;li&gt;Security vulnerabilities of primarily rendering HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Slate
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ianstormtaylor/slate" rel="noopener noreferrer"&gt;Slate.js&lt;/a&gt;, currently in beta, is a framework for building robust, rich text editors. Slate is made to be highly extensible, thus improving its native capabilities to create rich text editors. Slate is built with inspiration from tools including Quill and Draft.js. &lt;/p&gt;

&lt;p&gt;Slate poses to solve several bottlenecks with managing rich text content, some we have seen previously in this post. &lt;br&gt;
Slate aims to solve these challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serialization  to HTML &amp;amp; Markdown doesn’t ship out of the box&lt;/li&gt;
&lt;li&gt;Collaborative content creation is an afterthought&lt;/li&gt;
&lt;li&gt;Restrictive schema definition of document models&lt;/li&gt;
&lt;li&gt;Dynamic content creation should transcend beyond text, links, and media content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
Slate is distributed as a monorepo and can be installed along with its React plugin using npm or yarn with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install &lt;/span&gt;slate slate-react
    yarn add slate slate-react


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

&lt;/div&gt;

&lt;p&gt;Slate also requires the installation of  &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom&lt;/code&gt; as peer dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br&gt;
A Slate editor’s essential representation is a fundamental &lt;code&gt;contentEditable&lt;/code&gt; element, customized further until the desired functionality is achieved.&lt;/p&gt;

&lt;p&gt;To use Slate, we import the slate editor composer and components from its React plugin.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createEditor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Slate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Editable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;withReact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slate-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In the imports we have:&lt;br&gt;
&lt;strong&gt;Slate&lt;/strong&gt;: A context provider component for the Slate editor. It’s a controlled component that tracks the full editor state and updates.&lt;br&gt;
&lt;strong&gt;Editable&lt;/strong&gt;: Renders an editable rich text document, similar to &lt;code&gt;contentEditable&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;withReact&lt;/strong&gt;: Provides the editor with React specific functionalities&lt;/p&gt;

&lt;p&gt;Creating an &lt;code&gt;&amp;lt;SlateEditor/&amp;gt;&lt;/code&gt; component and rendering a simple editor, we have:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createEditor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Slate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Editable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;withReact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slate-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SlateEditor&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;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;withReact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createEditor&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;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paragraph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;We have some base content.&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="p"&gt;]);&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;React Editors&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Start editing to see Slate in action!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Slate&lt;/span&gt;
            &lt;span class="na"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Editable&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Slate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; hook maintains a consistent editor object during the component update. We initialized the &lt;code&gt;Slate&lt;/code&gt; controlled component’s state data with an array containing an object with a block and children. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Slate&lt;/code&gt; uses the default renderer, which outputs a &lt;code&gt;div&lt;/code&gt; to render the default paragraph content. The editor can be extended further using events, custom renderers, custom elements, and commands to include controls, filters, and much more.&lt;/p&gt;

&lt;p&gt;You can find out more on using &lt;a href="https://docs.slatejs.org/" rel="noopener noreferrer"&gt;Slate to build a fully-featured rich text editor similar to Medium and dropbox paper here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ships robust APIs and handlers to build out fully featured rich text editors&lt;/li&gt;
&lt;li&gt;Dynamic content blocks with types to further customize or abstract portions of the content &lt;/li&gt;
&lt;li&gt;Outputs plain JSON; hence serialization to other data formats is seamless&lt;/li&gt;
&lt;li&gt;Extensible with the use of plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires setup with a steep learning curve to handle simple content use cases&lt;/li&gt;
&lt;li&gt;Requires UI setup to operate controls in the editor&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Jodit-React
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://xdsoft.net/jodit/" rel="noopener noreferrer"&gt;Jodit&lt;/a&gt; is an open-source WYSIWYG editor written in TypeScript. &lt;a href="https://github.com/jodit/jodit-react" rel="noopener noreferrer"&gt;Jodit-react&lt;/a&gt;, a wrapper for Jodit, is a great WYSIWYG rich text editor that ships with controls to handle most rich text formatting, links, and tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
Install Jodit and jodit-react using npm and yarn with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install &lt;/span&gt;jodit jodit-react
    yarn add jodit jodit-react


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br&gt;
Here’s the sample usage below to render a rich text editor with default controls and a handler to update the component state using the &lt;code&gt;onBlur&lt;/code&gt; event.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;JoditEditor&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jodit-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Start writing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;readonly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&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;handleUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editorContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editorContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;React Editors&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Start editing to see some magic happen!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JoditEditor&lt;/span&gt;
            &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onBlur&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleUpdate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newContent&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="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We imported the required modules and set up a basic config for the editor. You can find &lt;a href="https://xdsoft.net/jodit/doc/options/" rel="noopener noreferrer"&gt;more editor config options here&lt;/a&gt;.&lt;br&gt;
We proceed to create a function to handle state updates with data from the editor. &lt;code&gt;&amp;lt;JoditEditor/&amp;gt;&lt;/code&gt; renders the editor, which looks like this:&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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610199878199_image.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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610199878199_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides themes and custom theme creation&lt;/li&gt;
&lt;li&gt;Easy to setup WYSIWYG editor for simple content requirements&lt;/li&gt;
&lt;li&gt;Provides custom controls and buttons to enhance the editor&lt;/li&gt;
&lt;li&gt;Allows the creation of custom plugins for editor extensibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Absence of block content with types for more in-depth content control&lt;/li&gt;
&lt;li&gt;It doesn’t support robust data requirements like embeds and collaborative content creation&lt;/li&gt;
&lt;li&gt;The content output is in HTML as typical with WYSIWYG editors, with potential security vulnerabilities when rendering the data using &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt; in React.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Portable Text
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/portabletext/portabletext" rel="noopener noreferrer"&gt;Portable text&lt;/a&gt; is a JSON-based open specification with a renewed approach to handling and presenting rich text in modern applications. Portable text is created to solve challenges in creating rich content and its presentation in various differing interfaces. &lt;/p&gt;

&lt;p&gt;Portable text content can be serialized into any content format. Its customizable and extensible data structure serves a limitless approach to constructing multi-level content either with data entities as siblings or children. &lt;/p&gt;

&lt;p&gt;Portable text returns content in the form of an array containing blocks of child content with a style, types, and &lt;em&gt;mark definitions - these are formats applied to content types.&lt;/em&gt; The JSON formatted portable text content is further transformed into any standard data format, including HTML and Markdown with serializers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity Studio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.sanity.io/studio" rel="noopener noreferrer"&gt;Sanity Studio&lt;/a&gt; is an open-source CMS with real-time collaboration on modern data requirements. Sanity utilizes portable text to serve block content created in the Sanity Studio. Portable text and the structured content approach of the Sanity Studio allow users to create various content models bordered on solving both domain and generalized content problems.&lt;/p&gt;

&lt;p&gt;Sanity Studio also offers the ability to extend content solutions with plugins, integrations, and interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity studio installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sanity has multiple official starters to get started on a project quickly. These include starters for JAMStack frameworks like Gatsby.js, Next.js, Eleventy, and Gridsome. There are starters for &lt;a href="https://create.sanity.io/?template=sanity-io%2Fsanity-template-gatsby-blog" rel="noopener noreferrer"&gt;Blogs&lt;/a&gt;, &lt;a href="https://create.sanity.io/?template=sanity-io%2Fsanity-template-nextjs-ecommerce" rel="noopener noreferrer"&gt;E-commerce&lt;/a&gt;, &lt;a href="https://create.sanity.io/?template=sanity-io%2Fsanity-template-gatsby-portfolio" rel="noopener noreferrer"&gt;Portfolio website&lt;/a&gt;, and a &lt;a href="https://create.sanity.io/?template=sanity-io%2Fsanity-template-kitchen-sink" rel="noopener noreferrer"&gt;landing page&lt;/a&gt; with data from Sanity Studio. We can find &lt;a href="https://create.sanity.io/" rel="noopener noreferrer"&gt;all starters here&lt;/a&gt; and even community starters.&lt;/p&gt;

&lt;p&gt;Alternatively, we can create a new project from scratch using &lt;code&gt;sanity init&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To do this, install sanity CLI globally with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @sanity/cli


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

&lt;/div&gt;

&lt;p&gt;On sanity CLI installation completion, proceed to create a Sanity account or login from the CLI with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    sanity login


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

&lt;/div&gt;

&lt;p&gt;Once we log in, we run &lt;code&gt;sanity init&lt;/code&gt;, follow the CLI prompts to create a new project. We’ll choose the default dataset configuration and any of the project templates. Here, we choose the blog template that ships with the schema.&lt;/p&gt;

&lt;p&gt;With the project’s successful setup, we change the directory into the project folder and run &lt;code&gt;sanity manage&lt;/code&gt;  to open the project in the browser, and it looks like this:&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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610202547923_image.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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610202547923_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To open the studio locally, in the project directory, we run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    sanity start


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

&lt;/div&gt;

&lt;p&gt;This command creates a local development server on &lt;a href="http://localhost:3333" rel="noopener noreferrer"&gt;http://localhost:3333&lt;/a&gt;. The local studio looks like this with the blog data schema:&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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610202813065_image.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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610202813065_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the studio’s &lt;strong&gt;Post&lt;/strong&gt; menu, we click the plus (+) icon on the top right corner to open the blog creation page. The blog editor contains a Portable Text rich text editor for structured block content. We create a sample blog content with title and text content.&lt;/p&gt;

&lt;p&gt;We’ll deploy a GraphQL API for the studio. This way, we can query data from the studio. We’ll do this with: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    sanity graphql deploy


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

&lt;/div&gt;

&lt;p&gt;A GraphQL API is created and deployed to sanity with a &lt;code&gt;default&lt;/code&gt; data tag. We’ll click the presented URL to see the schema in the GraphQL playground. Here’s a sample query to fetch the &lt;code&gt;title&lt;/code&gt; and JSON Portable text content in &lt;code&gt;bodyRaw&lt;/code&gt; of all blog posts:&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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610205527205_image.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%2Fpaper-attachments.dropbox.com%2Fs_E113D0606C08FF5A4201A92119BFD2AFC1066F011E0FDFEAAB76DB2B0CE3D018_1610205527205_image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity Studio Content in Gatsby.js&lt;/strong&gt;&lt;br&gt;
Gatsby.js is a tool for building super-fast single-page JAMstack applications. To use data from Sanity studio in a gatsby project, we require a source plugin for Gatsby.js. &lt;em&gt;gatsby-source-sanity&lt;/em&gt; solves this. &lt;/p&gt;

&lt;p&gt;We’ll install it with: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    npm &lt;span class="nb"&gt;install &lt;/span&gt;gatsby-source-sanity


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

&lt;/div&gt;

&lt;p&gt;In a gatsby project (different from the sanity studio project), we specify the plugin configuration in the plugins array of &lt;code&gt;gatsby-config.js&lt;/code&gt; with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;[...]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby-source-sanity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enter your project id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production || any other dataset on sanity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enter your sanity read token&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="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;Refresh the gatsby development server and open the graphql playground to see the source data from sanity. &lt;/p&gt;

&lt;p&gt;We can pull the content we want from sanity into our gatsby project, along with other content created on Sanity. &lt;/p&gt;

&lt;p&gt;In Gatsby projects, we use &lt;a href="https://www.npmjs.com/package/@sanity/block-content-to-react" rel="noopener noreferrer"&gt;block-content-to-react&lt;/a&gt; to serialize Portable Text.&lt;/p&gt;

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

&lt;p&gt;In this post, we discussed five popular React.js rich text editors. We discussed robust editors with block content to WYSIWYG editors for simple content requirements. Each of these is fit for specific use cases depending on the complexity of the project.&lt;/p&gt;

&lt;p&gt;We discussed portable text and the problems it solves in dynamic content creation - lastly, we setup Sanity studio with a blog schema that uses Portable Text. We created a GraphQL API for the content and utilized &lt;code&gt;gatsby-source-sanity&lt;/code&gt; to source the GraphQL data into a Gatsby.js project.&lt;/p&gt;

</description>
      <category>react</category>
      <category>richtext</category>
      <category>quill</category>
      <category>draft</category>
    </item>
    <item>
      <title>Setup Redux for Large React Projects - without Tears</title>
      <dc:creator>William</dc:creator>
      <pubDate>Mon, 01 Mar 2021 15:56:31 +0000</pubDate>
      <link>https://forem.com/chuloo/setup-redux-for-large-react-projects-without-tears-58m9</link>
      <guid>https://forem.com/chuloo/setup-redux-for-large-react-projects-without-tears-58m9</guid>
      <description>&lt;p&gt;For small React projects, it's cool passing props between React components, from the Arctic to Antarctica 😃. With increasing complexity, we pass a bit more props and possibly throw in React Context to manage some state data between nested sibling components.&lt;/p&gt;

&lt;p&gt;As the project grows, the need for a proper state management tool becomes unavoidable. This is the sweet spot for a tool like Redux in React projects. However, setting up Redux is considered herculean due to the amount of boilerplate required.&lt;/p&gt;

&lt;p&gt;In this post, we'll set up a redux store suitable for large projects without shedding tears. This post's scope doesn't cover setting up Thunk middleware for async actions or persisting a store.&lt;/p&gt;

&lt;p&gt;We'll focus mostly on store creation, project composition, entity reusability, and manageability. A considerable concern amongst developers using Redux in React projects is the convolution of the codebase with the increase in state variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Redux?
&lt;/h3&gt;

&lt;p&gt;Quick director cut for those unfamiliar with Redux. Redux is a robust state container for JavaScript applications. Peep the barrels in the banner image. Like they hold wine possibly in your cellar, Redux creates a box for application data in your JavaScript application.&lt;/p&gt;

&lt;p&gt;Redux creates an application data store and provides logic to retrieve and modify the stored data. Wondering how state management works on the bare minimum? I wrote &lt;a href="https://hackmamba.io/blog/2020/09/explaining-web-apps-state-management-like-abc/" rel="noopener noreferrer"&gt;this post about it using HTML and JavaScript.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With accompanying tools like React-Redux, state management in React apps becomes seamless. With state hoisted from components into the application layer, interactivity in your frontend app becomes almost limitless.&lt;/p&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;p&gt;Knowledge of JavaScript and React.js is required to follow through with this post. We'll create a simple counter app on CodeSandbox with data from the application state.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create a React Project
&lt;/h4&gt;

&lt;p&gt;Create a new CodeSandbox using the React starter by CodeSandBox. You can find the final code for this post here.&lt;/p&gt;

&lt;p&gt;The created project comes with boilerplate code with the app entry point in &lt;code&gt;src/index.js&lt;/code&gt; and the home page in &lt;code&gt;src/App.js&lt;/code&gt;. Basic CSS styles are written in &lt;code&gt;src/styles.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create the base HTML structure for the counter app with 2 buttons and a counter display in &lt;code&gt;App.js&lt;/code&gt;. Modify the file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello CodeSandbox&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Start editing to see some magic happen!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Counter is 0&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Decrement&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We wrapped all the app with &lt;code&gt;Provider&lt;/code&gt; and passed it props of the imported store.&lt;/p&gt;

&lt;h4&gt;
  
  
  Consume State
&lt;/h4&gt;

&lt;p&gt;If you made it this far, you have setup redux and can utilize the app state's data.&lt;/p&gt;

&lt;p&gt;react-redux provides two super useful hooks to store and retrieve data from redux. They are &lt;code&gt;useSelector&lt;/code&gt; and &lt;code&gt;useDispatch&lt;/code&gt;, to retrieve data and dispatch actions respectively. We'll modify &lt;code&gt;src/App.js&lt;/code&gt; to utilize these hooks in making the counter interactive. Do this with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useDispatch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IncrementCounterAction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./redux/counter/increment-counter-action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DecrementCounterAction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./redux/counter/decrement-counter-action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&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;dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDispatch&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;_handleIncrement&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="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IncrementCounterAction&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;_handleDecrement&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="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DecrementCounterAction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello CodeSandbox&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Start editing to see some magic happen!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Counter is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_handleIncrement&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_handleDecrement&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Decrement&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we imported the actions which will be dispatched on increment and decrement. We created two functions to handle the dispatch. The &lt;code&gt;counter&lt;/code&gt; data is also retrieved from the redux state with an initial value of 0. In the case there is a payload, this is passed as an argument to the action call.&lt;/p&gt;

&lt;p&gt;The increment and decrement functions are passed to the &lt;code&gt;onClick&lt;/code&gt; handler of the buttons to increment and decrement the counter variable, respectively.&lt;/p&gt;

&lt;p&gt;You can test out the buttons on end.&lt;/p&gt;

&lt;p&gt;Here's what it looks like now:&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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1607379454%2Fhackmamba%2FScreen_Shot_2020-12-08_at_2.17.19_AM.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%2Fres.cloudinary.com%2Fchuloo%2Fimage%2Fupload%2Fv1607379454%2Fhackmamba%2FScreen_Shot_2020-12-08_at_2.17.19_AM.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find &lt;a href="https://codesandbox.io/s/redux-boilerplate-2h87u" rel="noopener noreferrer"&gt;the CodeSandbox demo here.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;In this post, we set up a redux store with constants, reducers, and actions. The store data is utilized in a counter application.&lt;/p&gt;

&lt;p&gt;A key takeaway from this post is in the redux store setup and the separation of concerns. This ensures that when the application size increases and state variables abound, setting up new actions and reducers are seamless. Also, the codebase is maintainable.&lt;/p&gt;

&lt;p&gt;Here's to becoming better, and wearing a mask, for now. 😃&lt;/p&gt;

&lt;p&gt;William.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2020/12/setup-redux-for-large-react-projects-without-tears/" rel="noopener noreferrer"&gt;Hackmamba.&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AI Product Manager</title>
      <dc:creator>William</dc:creator>
      <pubDate>Tue, 23 Feb 2021 20:42:52 +0000</pubDate>
      <link>https://forem.com/chuloo/ai-product-manager-5ch2</link>
      <guid>https://forem.com/chuloo/ai-product-manager-5ch2</guid>
      <description>&lt;p&gt;I recently completed the &lt;a href="https://www.udacity.com/course/ai-product-manager-nanodegree--nd088"&gt;Artificial Intelligence Product Manager&lt;/a&gt; Nanodegree Program on Udacity and I'd like to share a summary of everything I learned with you. This also includes bits from my experience as a technical product manager.&lt;/p&gt;

&lt;p&gt;This all a huge dump from my mind, written from the first stroke to last on my keyboard so kindly excuse any details I may miss or depths I didn't hit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the AI program?
&lt;/h3&gt;

&lt;p&gt;It would be great to start with "why" and what motivated me to complete this program. In the past year, I've been working as a full-time product manager, sitting at the intersection of engineering and business and it's been fun. Solving problems is fun. However, I'd recently been thinking deeply about the future of technology and what turns it could take. No doubt, artificial intelligence will play a huge part in this future.&lt;/p&gt;

&lt;p&gt;With this in mind, I set to learn how artificial intelligence could directly solve human problems which in turn would drive the growth of businesses. The AI for Product Managers Nanodegree program on Udacity seemed a good fit. The recommended study by Udacity is 2 months. I completed it in 3 weeks, you can too if you try it out. 😃&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview of the program
&lt;/h3&gt;

&lt;p&gt;Along with building a real-world project proposal, the program focused on imparting knowledge of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is AI and its use cases&lt;/li&gt;
&lt;li&gt;When is utilizing Machine Learning relevant&lt;/li&gt;
&lt;li&gt;The business cases of AI solutions&lt;/li&gt;
&lt;li&gt;Machine learning models&lt;/li&gt;
&lt;li&gt;Data Annotation and Training&lt;/li&gt;
&lt;li&gt;Model assessment and model performance&lt;/li&gt;
&lt;li&gt;Business metrics assessment&lt;/li&gt;
&lt;li&gt;Designing AI products for longevity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following sections of this letter, I'll give a succinct explanation of each of the above-listed points.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is AI and its use cases?
&lt;/h3&gt;

&lt;p&gt;AI, short for artificial intelligence is the ability of machines to carry out actions that previously required human intelligence or knowledge. Simply put, if a machine is able to look at your face and tell if you're smiling or frowning and how happy you seem, then that's artificial intelligence.&lt;/p&gt;

&lt;p&gt;AI is used in numerous cases, anything that previously required human effort could be augmented or replaced with AI. The key here is &lt;strong&gt;performance&lt;/strong&gt;. Which is more performant, humans or machines? Advancements in the field have seen tremendous improvements in the performance of AI models where humans previously excelled. I expect the uptick to continue exponentially.&lt;/p&gt;

&lt;p&gt;While AI is a body of work on intelligent machines and systems, Machine learning is a subset of artificial intelligence where machines are able to learn and make decisions based on data fed to the machine. AI and ML will be used interchangeably throughout this text.&lt;/p&gt;

&lt;p&gt;An example use case of Machine learning is in identifying distinct defining patterns in images. This could be health X-rays, traffic signs, chemical color, substance visible quality, etc. These would normally require human effort, but with the computing power of machine learning systems, it's done faster.&lt;/p&gt;

&lt;p&gt;ML is currently employed in object recognition, audio/speech recognition, language detection amongst others.&lt;/p&gt;

&lt;h3&gt;
  
  
  When is it relevant to use Machine Learning?
&lt;/h3&gt;

&lt;p&gt;You may wonder, why should I bother with the ML buzz when I can get someone to do the same thing for half the cost of the technology.&lt;/p&gt;

&lt;p&gt;You are right.&lt;/p&gt;

&lt;p&gt;Technology by itself enhances existing solutions or proffers solutions entirely impossible previously. AI is utilized where higher efficiency is required to replace an existing process. For example in sorting mail during transport, a single person could properly identify and sort packages at 20 packages a minute. However, an AI-assisted system would perform text recognition on the destination address on each package and sort the packages at 50 packages a minute. More than doubling performance.&lt;/p&gt;

&lt;p&gt;If the introduction of artificial intelligence like any other technology doesn't improve the performance of your system and/or business then you could look to other optimization methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  The business cases of AI solutions
&lt;/h3&gt;

&lt;p&gt;What good is an AI system introduced to enhance a solution, if it doesn't contribute to the improvement of a business objective? No good you must think too. A crucial part of developing AI solutions for businesses as a product manager is to understand what key objectives are affected by the solution. Both positively and negatively. These form the business case.&lt;/p&gt;

&lt;p&gt;An AI solution could improve user experience but cost much more than the business can afford. Trade-offs have to be considered before deciding the usefulness of a solution.&lt;/p&gt;

&lt;p&gt;What do you intend to achieve with an AI product or solution and how will this drive a business objective? These objectives are listed and the impact on business outcomes is evaluated.&lt;/p&gt;

&lt;p&gt;Business objectives are specific and can be easily identified. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To improve user experience in the checkout process&lt;/li&gt;
&lt;li&gt;To increase conversion on the search page&lt;/li&gt;
&lt;li&gt;To reduce the number of call center agents required to assist customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These business objectives are beneficial to the business and/or users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Machine learning models
&lt;/h3&gt;

&lt;p&gt;To use machine learning solutions, a model is required. A machine learning model comprises a series of complex instructions trained using to produce specific outcomes. A model takes an input and returns an output after running the input through algorithms to make complex decisions.&lt;/p&gt;

&lt;p&gt;Excuse the french, a model is a system that is trained with data, given input, and it returns an output depending on its training and decision process.&lt;/p&gt;

&lt;p&gt;Examples of ML models include speech to text models, object character recognition models, and computer vision models.&lt;/p&gt;

&lt;p&gt;Models can either be built from scratch or a process called transfer learning is used to retrain an existing model. Transfer learning is a process whereby an existing trained model is retrained using the same model algorithms but with different data sets. In transfer learning, the expected inputs are similar and the predicted outcomes are based on the data used in retraining the model.&lt;/p&gt;

&lt;p&gt;Transfer learning is used over developing a model from scratch for multiple reasons. Building a machine model from scratch requires more resources and technical complexities. Transfer learning systems on the other hand are offered by various 3rd party providers including Google and IBM. Setting up transfer learning models require less setup overhead. However, transfer learning comes with a deficiency in customizing and extending the capability of the model. Also, there is the issue in transfer learning models of cost and managing the model when huge datasets are fed through.&lt;/p&gt;

&lt;p&gt;For the purpose of the nanodegree, transfer learning is used. &lt;a href="https://cloud.google.com/automl"&gt;Google AutoML&lt;/a&gt; is the platform of choice to generate a model to detect pneumonia in X-ray images, for the model development exercise. The AutoML Vision model is used to classify the images.&lt;/p&gt;

&lt;p&gt;A machine learning model is to be created to differentiate between two classes of images, normal and pneumonia. When an image is fed into the system, it should return the class of the image with the level of confidence it has in its prediction.&lt;/p&gt;

&lt;p&gt;A class is a decision outcome of the model. A model is fed an input (image) and a class is expected as output.&lt;/p&gt;

&lt;p&gt;To achieve this, the model is to be trained with data from both classes and tested before use.&lt;/p&gt;

&lt;p&gt;The following important data considerations are made when setting up a model.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unbiased Data
&lt;/h4&gt;

&lt;p&gt;The data must be unbiased. The same amount of each required outcome class is to be used in training the model. Bias in the data leads to overtraining or under-training of one class over the other. This is also reflected in the confidence of the model when making predictions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Quantity of Data
&lt;/h4&gt;

&lt;p&gt;The more the data class, the more the ML model is able to accurately predict the same class with high confidence.&lt;/p&gt;

&lt;h4&gt;
  
  
  Data Disparity
&lt;/h4&gt;

&lt;p&gt;For each class, all kinds of data within the class should be provided. All possible edge cases and forms of that kind of data should be provided. Also, these individual subset groups should also be unbiased and in large quantities to improve the confidence of the model in making predictions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Data Accuracy
&lt;/h4&gt;

&lt;p&gt;The model is only as accurate as the data it is trained with. Avoid using the wrong data in training the model. Wrong data will lead to confusion of the model thereby reducing its performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data annotation and Training
&lt;/h3&gt;

&lt;p&gt;Depending on the model outcome, the data required for training may require annotation. Annotation is the process of properly assigning labels to uncategorized or scattered data. These labels are required in training the model. Other forms of data may already be annotated through other means and do not require annotation by physical methods or human input.&lt;/p&gt;

&lt;p&gt;Annotation is done by humans or existing systems (possibly AI-powered too) to accurately label the training data with the required classes. Services like &lt;a href="https://appen.com/"&gt;Appen&lt;/a&gt;, provide systems to annotate data.&lt;/p&gt;

&lt;p&gt;After data is annotated and prepared with the right considerations, it is fed to the model to be trained.&lt;/p&gt;

&lt;p&gt;Test data is set aside to test the performance of the model. This data isn't used in training the model and is entirely new to the trained system. With this test data, the performance of the model can be accurately assessed. The test data is also required to be unbiased and should cover all test cases to ensure all outcomes and edge cases of the model are tested.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model assessment and model performance
&lt;/h3&gt;

&lt;p&gt;How well is the model able to predict the desired outcome? This is measured using various parameters. Two important measures are Precision and Recall.&lt;/p&gt;

&lt;p&gt;Precision is the ability of a model to predict an outcome from all predicted outcomes. Recall is the ability of a model to identify the occurrence of a relevant outcome.&lt;/p&gt;

&lt;p&gt;Precision is calculated as the ratio of true positives (correct predictions) to total predictions where Recall is the ratio of true positives (total correct predictions) to the total number of the class data (ie the total possible occurrence of the class - true positives + false negatives).&lt;/p&gt;

&lt;p&gt;For a model with multiple classes, the Recall of the model is the average of all the recalls of its individual classes. This is the same for model Precision.&lt;/p&gt;

&lt;p&gt;The recall and precision are important values in measuring model performance. For certain models, you would need a high precision value, for example, in ID verification systems. Whereas in X-ray scanning systems for detecting pneumonia, you would need to have a high recall value, as you would want more false negatives in the pool (true values but predicted as false). This way even patients with a slight chance of pneumonia are sent to the doctor for further evaluation instead of leaving them out.&lt;/p&gt;

&lt;p&gt;Another metric for model evaluation is the F1 score which combines Recall and precision. The formula for F1 score is &lt;code&gt;(2 * precision * recall)/(precision + recall)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business metrics assessment
&lt;/h3&gt;

&lt;p&gt;Once an AI product or feature has been developed, it needs to be tested against defined business metrics. These metrics are formulated from the business cases stated earlier. The product metrics must be specific and measurable. Examples of good metrics are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase user acquisition by 10% month on month&lt;/li&gt;
&lt;li&gt;Reduce operating expenditure in customer service by 30%&lt;/li&gt;
&lt;li&gt;Improve the NPS score by 40%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Business metrics should be measured before and after deploying a model. A way to ascertain the impact of an ML system on a product is to conduct A/B tests. These tests are run on sampled live users. A competing portion (new model or process) is put in a test with an existing portion. The winner after evaluation against set metrics is used as the final version in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designing AI products for longevity
&lt;/h3&gt;

&lt;p&gt;Like every other product, multiple factors are considered to ensure that multiple strategic intents defined by all stakeholders are met. Also, product development efforts must align with the high-level product vision.&lt;/p&gt;

&lt;p&gt;In developing ML-powered products, the data is largely considered when building for the long term. The following questions come to mind:&lt;/p&gt;

&lt;p&gt;How will the data change over time? What is the cost of acquiring the data? Does running the model in the long term align with the product vision or multiple changes have to occur at certain stages in the life of the product? What does the roadmap for the AI solutions look like?&lt;/p&gt;

&lt;p&gt;These and all other product management questions have to be answered and all should be within the frame of the product vision.&lt;/p&gt;

&lt;p&gt;Building out successful products requires a strong feedback loop from the customer and the business, informing the product. There should be adequate mechanisms in place to ensure this feedback is incorporated in every step of an AI product iteration. From data annotation, model training, and testing to model iteration for performance.&lt;/p&gt;

&lt;p&gt;Human in the loop (HITL) is normally introduced in ML systems to serve as feedback mechanisms where an ML system is deficient. The data from the human is used in further training the ML system for improved performance.&lt;/p&gt;

&lt;p&gt;Lastly, like I would say, "there is no one defined route/blueprint to building and shipping every product", however, certain entities are common in all products. Pick out the 'useful commons', hone your process, track performance, and ship better!&lt;/p&gt;

&lt;p&gt;Here's to becoming better.&lt;/p&gt;

&lt;p&gt;William.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2020/11/ai-for-product-managers/"&gt;Hackmamba&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>management</category>
      <category>machinelearning</category>
      <category>ai</category>
      <category>productmanagement</category>
    </item>
    <item>
      <title>Deploy a Gatsby Site to Digital Ocean in 7 Steps</title>
      <dc:creator>William</dc:creator>
      <pubDate>Wed, 17 Feb 2021 17:26:45 +0000</pubDate>
      <link>https://forem.com/chuloo/deploy-a-gatsby-site-to-digital-ocean-in-7-steps-5411</link>
      <guid>https://forem.com/chuloo/deploy-a-gatsby-site-to-digital-ocean-in-7-steps-5411</guid>
      <description>&lt;p&gt;Asides the smooth development experience of using JavaScript, APIs, and Markup to build out JAMstack apps, the deployment process is also splendid. Multiple providers are available to deploy JAMstack, and we will discuss a preferred top 5.&lt;/p&gt;

&lt;p&gt;In this post, we'll deploy a sample Gatsby.js application to Digital Ocean using the App Platform for static sites, in seven steps.&lt;/p&gt;

&lt;p&gt;You can find the sample Gatsby repository with the &lt;a href="https://github.com/Chuloo/sample-jamstack-site"&gt;default starter here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like most hosting providers for JAMstack apps, Digital ocean provides a generous free tier to host and manage web apps. Digital Ocean issues a $100 credit on signup. The free plan covers the requirements to try out the platform. However, two offerings stood out, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited team members&lt;/li&gt;
&lt;li&gt;DDoS protection
We'll proceed to the seven steps required to deploy a Gatsby.js app to Digital Ocean.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create an account
&lt;/h3&gt;

&lt;p&gt;Create a Digital Ocean account or sign in to an existing &lt;a href="https://cloud.digitalocean.com/login"&gt;one here.&lt;/a&gt;&lt;br&gt;
Once you create a new account, you'll receive $100 free credits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a new app deployment
&lt;/h3&gt;

&lt;p&gt;On the top right corner, click the "Create" button to select an option. For our JAMstack use case, we'll use the "Apps" option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AKKmztPl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/chuloo/image/upload/v1611655186/hackmamba/deployment-to-do/Screen_Shot_2021-01-26_at_12.25.30_PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AKKmztPl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/chuloo/image/upload/v1611655186/hackmamba/deployment-to-do/Screen_Shot_2021-01-26_at_12.25.30_PM.png" alt="alt text" width="543" height="738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add a repository source
&lt;/h3&gt;

&lt;p&gt;App platform deploys applications from remote repositories (currently GitHub and GitLab). This also ensures we can set up a standard CI/CD pipeline that redeploys the code changes in the repository.&lt;/p&gt;

&lt;p&gt;In this step, select your repository provider. We use GitHub as that's the source of the project repository. A prompt is opened in a new window to install Digital Ocean to an organization on your verified GitHub account. Follow the prompts and proceed to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Select a project repository
&lt;/h3&gt;

&lt;p&gt;With Digital Ocean installed, select a repository from the dropdown of repositories. Only repositories you have access to, belonging to organizations with Digital Ocean installed are displayed.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TUYj98x3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/chuloo/image/upload/v1611655792/hackmamba/deployment-to-do/Screen_Shot_2021-01-26_at_2.09.37_PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TUYj98x3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/chuloo/image/upload/v1611655792/hackmamba/deployment-to-do/Screen_Shot_2021-01-26_at_2.09.37_PM.png" alt="alt text" width="880" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Configure the app
&lt;/h3&gt;

&lt;p&gt;Next, select a name, server region, and deployment branch for your app. An important option to choose is the auto-deployment option on code changes. Tick the checkbox if you want this.&lt;/p&gt;

&lt;p&gt;Digital ocean detects the application technology and prefills the next page with the application options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Configure build settings
&lt;/h3&gt;

&lt;p&gt;Set up your build command for this project, &lt;code&gt;yarn build&lt;/code&gt;, which is prefilled, will suffice. Add your environment variables to the project, if any. Include the output/build directory. An omission will lead to an &lt;code&gt;auto&lt;/code&gt; option selected, which detects the project's build directory. Click the &lt;em&gt;next&lt;/em&gt; button to proceed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Select a plan and deploy
&lt;/h3&gt;

&lt;p&gt;On this page, select a plan for the project. The starter plan is just enough for this demo. You can explore other available paid plans if it matches your requirement. Click the &lt;em&gt;launch starter app&lt;/em&gt; button to deploy the app.&lt;/p&gt;

&lt;p&gt;The application deployment took about 9 minutes to complete. Several build, and optimization improvements can be made to deploy in lesser time.&lt;/p&gt;

&lt;p&gt;The resulting app is served super fast, customary with Digital Ocean deployed sites served over a CDN.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://sample-jamstack-site-xxrc6.ondigitalocean.app/"&gt;bare deployed Gatsby site here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B31Ffgfb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/chuloo/image/upload/v1611655186/hackmamba/deployment-to-do/Screen_Shot_2021-01-26_at_12.39.40_PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B31Ffgfb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/chuloo/image/upload/v1611655186/hackmamba/deployment-to-do/Screen_Shot_2021-01-26_at_12.39.40_PM.png" alt="alt text" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Summary&lt;br&gt;
In this post, we deployed a starter Gatsby site to Digital ocean in seven steps, from account creation to live site. In the next post, we'll deploy to another hosting provider. If you're reading this, you could share with me your preferred provider to be featured.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2021/01/deploy-a-gatsby-site-to-digital-ocean-in-7-steps/"&gt;Hackmamba&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gatsby</category>
      <category>jamstack</category>
      <category>api</category>
    </item>
    <item>
      <title>Never 'Why?' but 'How?'</title>
      <dc:creator>William</dc:creator>
      <pubDate>Mon, 15 Feb 2021 17:57:16 +0000</pubDate>
      <link>https://forem.com/chuloo/never-why-but-how-1e4m</link>
      <guid>https://forem.com/chuloo/never-why-but-how-1e4m</guid>
      <description>&lt;p&gt;Working with people can get pretty tough. It could be on a school project, at work, or even by just a normal casual conversation.&lt;/p&gt;

&lt;p&gt;The persistence of differing views is a key contributor to multiple disagreements between people. Over time working with people and currently on my product team, I encounter numerous unavoidable challenges with both internal and external stakeholders.&lt;/p&gt;

&lt;p&gt;Previously, I thought we have different interests and views. However, after a thorough empathetic retrospective, I realize we sometimes have similar interests only humanity in me won't let me see beyond my nose and to their view.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does "Why" make people feel?
&lt;/h3&gt;

&lt;p&gt;Humans are in touch with their emotions and are inherently irrational beings. This drives our conversation and decision process. We love to be heard and like my dad would say "No one likes to be told that their food tastes bad".&lt;/p&gt;

&lt;p&gt;Try asking 'why' for every ask you get in a conversation. I hope you don't get punched in the face. People would likely pick offense or feel some resentment at the very least when you ask 'why'. Even when asked reasonably.&lt;/p&gt;

&lt;p&gt;Working with teams and on calls, I would ask "Why" for a lot of requests. I mean, that's what the books say is the Job of a product manager. I got stuff done but with more friction. I realized the following when speaking about a feature proposal or suggestion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced buy-in from the proposer of the idea or the team&lt;/li&gt;
&lt;li&gt;Lowered confidence to validate the suggestion&lt;/li&gt;
&lt;li&gt;Less enthusiasm to even explain the reason behind the idea&lt;/li&gt;
&lt;li&gt;Overall resentment and pushback from the other party.&lt;/li&gt;
&lt;li&gt;Less room for collaboration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Something just seemed aggressive with the word 'Why'. Especially if you're a key decision-maker.&lt;/p&gt;

&lt;p&gt;I did a lot of retrospective and some research on how to approach requests and negotiating to a "that's right" from all parties. I read the book "Never Split the Difference" by Chris Voss. I picked a very clever tactic that worked almost instantly.&lt;/p&gt;

&lt;p&gt;Here comes the savior.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Important "How"
&lt;/h3&gt;

&lt;p&gt;Chris Voss in his book stated the need to use How instead of Why in negotiations. It instantly displays empathy and a form of agreement to see reason before commitment.&lt;/p&gt;

&lt;p&gt;I sorted to apply this negotiation skill to product development with my teammates and it worked almost instantly. I reframed feature questions from something like "Why should we create an invoice generator at this time?" to "How will an invoice generator benefit us at this time?".&lt;/p&gt;

&lt;p&gt;With 'How', it's clear I'm no longer questioning the request on the surface but trying to understand the underlying reason behind the request. Also, it is an instant call for collaboration, the other party does have the work to validate the idea by providing specific reasons.&lt;/p&gt;

&lt;p&gt;Little change, big difference.&lt;/p&gt;

&lt;p&gt;I changed "Why do you think this is important to our business?" to "How will this benefit our business?". A common interest is declared and we move from what seems like an accusation to a call for an investigation. The collaboration between teams increased and everyone is always rallied around a shared interest.&lt;/p&gt;

&lt;p&gt;A common use of "Why" by product managers and leaders is "Why are we delayed on this?" "Why are we here on the timeline". These are instantly aggressive. Replacing those with "How are we delayed on this" and "How are we here on the timeline", still shows the importance of the situation but requests valid causation which leads to a viable line of action.&lt;/p&gt;

&lt;p&gt;Another alternative to using "How" is its sibling, "What". This also produces an open-ended question and provides an investigative stance rather than a pushback accusatory stance. "Why should we put the button on the left" becomes "What do we intend to achieve with the button on the left".&lt;/p&gt;

&lt;p&gt;Be careful not to sound dumb when asking "How" without context. Plainly throwing "How?" to the wind could be returned with "How what?". Paradise of confusion yeah.&lt;/p&gt;

&lt;p&gt;"Why" still has its place, however, it's used sparingly, and understanding the emotional triggers it plucks when used, cannot be overly emphasized.&lt;/p&gt;

&lt;p&gt;Here's to becoming better 🥂&lt;/p&gt;

&lt;p&gt;William&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2020/11/never-why-but-how/"&gt;Hackmamba.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>management</category>
      <category>people</category>
      <category>tech</category>
    </item>
    <item>
      <title>Aggregate Multiple API Requests with Promise.all()</title>
      <dc:creator>William</dc:creator>
      <pubDate>Thu, 11 Feb 2021 07:37:29 +0000</pubDate>
      <link>https://forem.com/chuloo/aggregate-multiple-api-requests-with-promise-all-2i</link>
      <guid>https://forem.com/chuloo/aggregate-multiple-api-requests-with-promise-all-2i</guid>
      <description>&lt;p&gt;I promise you’ll get a summary of this post at the end.&lt;br&gt;
Asynchronous operations are at the backbone of implementing interactivity in modern JavaScript applications. These are used when making API calls, network requests, or even via a basic delay function.&lt;/p&gt;

&lt;p&gt;Asynchronous operations utilize promises, callback functions, or async/await. Commonly, these operations are singular and do not require aggregation of multiple async operations into one.&lt;br&gt;
Recently, I started working to build an aggregation service that utilizes multiple 3rd party APIs and aggregates the resulting data. In this post, we’ll learn how we make concurrent async requests using &lt;code&gt;Promise.all()&lt;/code&gt; in JavaScript. Also, we'll learn how to limit these requests to run in certain groups/portions at a time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Promise.all()
&lt;/h3&gt;

&lt;p&gt;An async function to fetch data from an API typically looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchData&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;res&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./names.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we utilize Axios, a promise-based HTTP client, to make an HTTP request to retrieve data in a local json file. An alternative to using async/await is to use the &lt;code&gt;.then()&lt;/code&gt; method of a promise.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;Promise.all()&lt;/code&gt;, we handle multiple similar requests concurrently and return a single aggregated response. Promise.all() takes an iterable (an array) of promises. It returns an array containing each promise resolution in the same order.&lt;/p&gt;

&lt;p&gt;If any of the promises in Promise.all() is rejected, the promise aggregation is rejected. Here's an example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./names.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./names-mid.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./names-old.json&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;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Promise failed&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sample is more elaborate and in a try/catch block to catch any failure in the promise resolution.&lt;/p&gt;

&lt;p&gt;Promise.all() doesn't resolve the promises and only aggregates the promises into an array with a single resolution. I'll cut the crap; this means you need to use Promise.all() with an &lt;code&gt;await&lt;/code&gt; or &lt;code&gt;.then()&lt;/code&gt; to resolve it. 😁&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.flat()&lt;/code&gt; is a useful array method that flattens the array. Previously, this would be done with a forloop or reduce function.&lt;/p&gt;

&lt;p&gt;An alternative with the &lt;code&gt;fetch&lt;/code&gt; API looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./names.json&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="s2"&gt;./names-mid.json&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="s2"&gt;./names-old.json&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;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Promise failed&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After using &lt;code&gt;fetch()&lt;/code&gt;, &lt;code&gt;.json()&lt;/code&gt; is required to parse the response and it also returns a promise! Multiple promises, this is becoming a telenovela!&lt;/p&gt;

&lt;p&gt;Another promise.all is required to aggregate the response.&lt;/p&gt;

&lt;p&gt;To better understand the effect of &lt;code&gt;Promise.all&lt;/code&gt;, we'll create a timing function that resolves a promise after a certain period.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observing with timing functions
&lt;/h3&gt;

&lt;p&gt;We'll create three promises with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&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;promise2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;8000&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;promise3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each promise resolves at different times of five, eight, and two seconds respectively.&lt;/p&gt;

&lt;p&gt;Calling each function separately in an async/await will return the resolved value of each after the set period. Aggregating the result will require further JavaScript operation to build an array.&lt;/p&gt;

&lt;p&gt;Calling all in &lt;code&gt;Promise.all()&lt;/code&gt; will resolve them all at the same time. In this case, in the time the function requiring the most time executes - 8 seconds.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;Promise.all()&lt;/code&gt;, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchAsyncData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;promise1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;promise2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;promise3&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="nx"&gt;res&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;It's an efficient and cleaner code for me. 😃&lt;/p&gt;

&lt;h3&gt;
  
  
  Limiting concurrency
&lt;/h3&gt;

&lt;p&gt;Still, on efficiency, you may want to make large numbers of concurrent requests. Rather than make them all at once, it would be efficient to chunk them.&lt;/p&gt;

&lt;p&gt;A useful npm package I found to do this is &lt;a href="https://www.npmjs.com/package/p-limit"&gt;p-limit.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can add it to your project using npm or yarn with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;

&lt;span class="nx"&gt;yarn&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a limit and specify concurrency count with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pLimit&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;p-limit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this limit in the promise with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;limit&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;promise1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;promise2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;promise3&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 block runs two promises at a time.&lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="https://codesandbox.io/s/dazzling-buck-lgzgz?file=/src/App.js"&gt;CodeSandbox link with all the code blocks running in a React app and logging data to the console.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Just like promises in JavaScript, you knew this summary was coming. I told you at the beginning. This is just like promises in JavaScript. In this post, we saw how to make aggregated promise resolutions using &lt;code&gt;Promise.all()&lt;/code&gt; and limit the concurrency where necessary using p-limit.&lt;/p&gt;

&lt;p&gt;Other promise methods to check out include:&lt;/p&gt;

&lt;p&gt;Promise.allSettled()&lt;br&gt;
Promise.any()&lt;br&gt;
Promise.race()&lt;br&gt;
Here's to becoming better. 🥂&lt;/p&gt;

&lt;p&gt;William&lt;/p&gt;

</description>
      <category>programming</category>
      <category>react</category>
      <category>hooks</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Manage Functionalities in Large Apps using Custom React Hooks</title>
      <dc:creator>William</dc:creator>
      <pubDate>Tue, 09 Feb 2021 16:14:07 +0000</pubDate>
      <link>https://forem.com/chuloo/manage-functionalities-in-large-apps-using-custom-react-hooks-1dk3</link>
      <guid>https://forem.com/chuloo/manage-functionalities-in-large-apps-using-custom-react-hooks-1dk3</guid>
      <description>&lt;p&gt;Since the introduction of React hooks, the creation and utilization of functional components became even more seamless. With &lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;useState&lt;/code&gt; lifecycle methods previously available to class components are also available in functional components.&lt;/p&gt;

&lt;p&gt;React's very purpose is to provide reusable blocks of code that form the various parts of an application. In this post, we'll explore how to use custom hooks to abstract component functionality reusable across a React application.&lt;/p&gt;

&lt;p&gt;To follow through with this post, you should be conversant with React.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use custom hooks
&lt;/h3&gt;

&lt;p&gt;You may wonder why you should even bother with writing custom React hooks when we can write your state and effect logic in the component and get to building the UI.&lt;/p&gt;

&lt;p&gt;You are right.&lt;/p&gt;

&lt;p&gt;It would be best if you mostly used a custom hook when you need to abstract a frequently used component functionality utilizing state and effect logic. Custom hooks are primarily present in large applications with multiple repetitive portions.&lt;/p&gt;

&lt;p&gt;For example, in a b2b e-commerce marketplace application, you may require fetching order data or seller information in multiple components. You can handle this particular fetching operation every time a component requires the data, or you can make a hook to handle it. The same applies to fetching location data in an application where user location is required in multiple components. Here are some reasons why I use custom hooks in large projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides useful abstraction as the same hook can be used across multiple components.&lt;/li&gt;
&lt;li&gt;Side effects like utility function calls, application state update, and singular hook requirements are managed independently with cleanups.&lt;/li&gt;
&lt;li&gt;You can use multiple hooks in one component without clutter.&lt;/li&gt;
&lt;li&gt;In Typescript, you want to have all the types in one place also, and not bloat the component code for readability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't have to handle this reusability, excuse my firm opinion, avoid the hasty abstraction, and don't use custom hooks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure of custom hooks
&lt;/h3&gt;

&lt;p&gt;Custom hooks are simply functions that encapsulate React &lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;useState&lt;/code&gt; APIs.&lt;br&gt;
They take parameters as specified and return data. The data could be an array, object, and primitive data types as specified.&lt;/p&gt;

&lt;p&gt;Within the hook, all the magic happens. This hook is used across components. The result is a cleaner and well-organized codebase.&lt;/p&gt;

&lt;p&gt;Here's what a custom hook looks like that fetches data for an order, showing the various parts in comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// hook definition&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useGetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// component state creation&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;orderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOrderId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;hookData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHookData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Function to run on first load&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// fetch data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;orderData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;orderData&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;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;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;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&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="nx"&gt;setHookData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// handle cleanup&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;unMountFn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// hooks return array&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hookData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;setOrderId&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// export hooks&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetOrder&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the snippet above, we can see the hook has the following parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Module import (useState &amp;amp; useEffect)&lt;/li&gt;
&lt;li&gt;Function arguments restructuring&lt;/li&gt;
&lt;li&gt;State creation&lt;/li&gt;
&lt;li&gt;Component mount logic in useEffect&lt;/li&gt;
&lt;li&gt;Component unmount logic (returned in useEffect)&lt;/li&gt;
&lt;li&gt;Component update variable&lt;/li&gt;
&lt;li&gt;Hooks return data&lt;/li&gt;
&lt;li&gt;Hooks export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This hook depicts a data fetching operation on receipt/update of an input variable &lt;code&gt;orderId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of fetching data in &lt;code&gt;useEffect&lt;/code&gt;, you could use a web API to transform data, and you could store data in the application state (if it's a valid use case) or call a utility function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom hooks in action
&lt;/h3&gt;

&lt;p&gt;Below is the hook we shared earlier to fetch an order data in use. With a familiar file name of &lt;code&gt;useGetOrder.js&lt;/code&gt;, we have the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// API call to get data&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./order.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// unmount Function&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;unMountFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// handle any cleanup process&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// hook definition&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useGetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// component state creation&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;orderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOrderId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;hookData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHookData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Function to run on first load&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// fetch data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;orderData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;orderData&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;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;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;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&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="nx"&gt;setHookData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// handle cleanup&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;unMountFn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// hooks return array&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hookData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;setOrderId&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// export hooks&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetOrder&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the hook, we created functions to fetch data from a local json file, a function to be called on component destruction, and the hook's definition.&lt;/p&gt;

&lt;p&gt;The hook function takes an input, and in the hook definition, we create state variables to hold the input data, loading state, and hooks data.&lt;/p&gt;

&lt;h4&gt;
  
  
  NB: The input data in this function is for reference and not utilized in the hooks logic
&lt;/h4&gt;

&lt;p&gt;The hook returns an array containing an object in the first index to retrieve the loading state and the hook data. &lt;code&gt;setOrderId&lt;/code&gt;, which modifies the input data, is assigned the second index.&lt;/p&gt;

&lt;p&gt;This hook is used in a component to fetch order data like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetOrder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../hooks/useGetOrder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HomeOrder&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hookData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;setOrderID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useGetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home Order&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Fetching order ⏳&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;ID: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Payment Captured: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paymentCaptured&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;True&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="s2"&gt;False&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Amount: $&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalAmount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Shipping Fee: $&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shippingFee&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Shipping Address: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shippingAddress&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;User ID: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Order Items&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hookData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; - $&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HomeOrder&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data, once fetched, can be used in the component. Rather than have the full state and mount logic in the component, we now have it as a hook that can be used by multiple components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NB: Just as you cannot use native React hooks outside of a React component, custom hooks containing &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; also cannot be used outside a react component&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/custom-hooks-demo-01qjd"&gt;Here's the final Codesandbox with the demo.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For large projects, you could do several optimizations and customizations to improve user experience and flexibility. These include:&lt;/p&gt;

&lt;p&gt;Having a wrapper for custom hooks with Types and generic configurations.&lt;br&gt;
Abstracting mount, unmount, error, and loading functions as parameters in the hooks definition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this post, we saw how to create a custom hook to handle reusable component logic in a React app. We also learned why we use custom hooks and how custom hooks look.&lt;/p&gt;

&lt;p&gt;To a better 2021, and happy new year!&lt;/p&gt;

&lt;p&gt;William.&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://hackmamba.io/blog/2021/01/manage-functionalities-in-large-apps-using-custom-react-hooks/"&gt;Hackmamba&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>hooks</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
