<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Methmi</title>
    <description>The latest articles on DEV Community by Methmi (@methmi).</description>
    <link>https://dev.to/methmi</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%2F915647%2F5851d9c9-dce1-4e84-a81f-4b5ad80b0040.png</url>
      <title>DEV Community: Methmi</title>
      <link>https://dev.to/methmi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/methmi"/>
    <language>en</language>
    <item>
      <title>The joy of validating with Joi</title>
      <dc:creator>Methmi</dc:creator>
      <pubDate>Fri, 23 Sep 2022 03:58:13 +0000</pubDate>
      <link>https://dev.to/methmi/the-joy-of-validating-with-joi-51ej</link>
      <guid>https://dev.to/methmi/the-joy-of-validating-with-joi-51ej</guid>
      <description>&lt;p&gt;Validation is a crucial step. But one look at the lines of IFs spawning from endless checks could send us over to NPM, hoping to find the perfect library.&lt;/p&gt;

&lt;p&gt;And one of the validation libraries you would find is Joi. And like its name, it’s a joy to use.&lt;/p&gt;

&lt;p&gt;With Joi, you can&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Describe your data using a simple, intuitive and readable language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So to ensure some user input contains a name and a valid email, it’s simply&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;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;minDomainSegments&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;span class="na"&gt;tlds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;com&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;net&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This code block validates an input to have a &lt;code&gt;name&lt;/code&gt; property with a number of characters between 3 and 30, and an &lt;code&gt;email&lt;/code&gt; with two domain parts (sample.com) and a top level domain (TLD) of either .com or .net.&lt;/p&gt;

&lt;p&gt;But to get a better view of what Joi has to offer, let’s see how we could build a simple form that validates a user’s input according to a schema.&lt;/p&gt;
&lt;h3&gt;
  
  
  A Simple Form Validation
&lt;/h3&gt;

&lt;p&gt;Installing Joi is as easy as running:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i joi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After importing Joi at the top of your file with,&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;Joi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joi&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;Joi can be used by first constructing a schema, then validating a value against the constructed schema.&lt;/p&gt;

&lt;p&gt;For this example let’s assume that we already have four text fields taking in a user’s name and email and asks to enter a password twice.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybyoq3fk52vzll22mqya.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybyoq3fk52vzll22mqya.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
A simple form built with Material UI



&lt;p&gt;Now to create the schema that Joi will validate against. Since a schema is designed to resemble the object we expect as an input, the schema for our four property form data object will look 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;objectSchema&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="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;alphanum&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;

    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;minDomainSegments&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;span class="na"&gt;tlds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;com&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;net&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="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^[a-zA-Z0-9]{3,30}$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string.pattern.base&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Password should be between 3 to 30 characters and contain letters or numbers only`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string.empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Password cannot be empty`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;any.required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Password is required`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;

    &lt;span class="na"&gt;repeatPassword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;any.only&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;The two passwords do not match&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;any.required&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;Please re-enter the password&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;According to this schema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; is validated to be:

&lt;ul&gt;
&lt;li&gt;an alphanumeric string&lt;/li&gt;
&lt;li&gt;between 3 to 30 characters&lt;/li&gt;
&lt;li&gt;a required field&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;email&lt;/code&gt; is checked to have :

&lt;ul&gt;
&lt;li&gt;two domain parts (sample.com)&lt;/li&gt;
&lt;li&gt;a top level domain (TLD) of either .com or .net&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Custom Error Messages
&lt;/h3&gt;

&lt;p&gt;The fields &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt; use default error messages:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk31ejq6yo5dh2161monz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk31ejq6yo5dh2161monz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But the fields &lt;code&gt;password&lt;/code&gt; and &lt;code&gt;repeatPassword&lt;/code&gt; use &lt;code&gt;.messages()&lt;/code&gt; to return a custom error message for a set of specific error types.&lt;/p&gt;

&lt;p&gt;For example, the custom error messages for the &lt;code&gt;password&lt;/code&gt; field are:&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Password should be between 3 to 30 characters and contain letters or numbers only`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Password cannot be empty`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Password is required`&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 first one is a custom message for an error of type &lt;code&gt;string.pattern.base&lt;/code&gt;, if the entered value does not match the RegExp string (since the &lt;code&gt;password&lt;/code&gt; field is validated with a RegExp).&lt;/p&gt;

&lt;p&gt;Likewise, if a an error of type &lt;code&gt;string.empty&lt;/code&gt; is returned (the field is left blank) the custom error message “Password cannot be empty” is shown instead of the default.&lt;/p&gt;

&lt;p&gt;Moving on to &lt;code&gt;repeatPassword&lt;/code&gt;, &lt;code&gt;Joi.valid()&lt;/code&gt; makes sure that the only valid value allowed for the &lt;code&gt;repeatPassword&lt;/code&gt; field is whatever the user data is for the &lt;code&gt;password&lt;/code&gt; field. The custom error message shown for an &lt;code&gt;any.only&lt;/code&gt; error type is shown when the entered value does not match the provided allowed value, which is &lt;code&gt;userData.password&lt;/code&gt; in this case.&lt;/p&gt;

&lt;p&gt;The full list of possible errors in Joi can be viewed here:&lt;br&gt;
&lt;a href="https://github.com/hapijs/joi/blob/master/API.md#list-of-errors" rel="noopener noreferrer"&gt;https://github.com/hapijs/joi/blob/master/API.md#list-of-errors&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Validating the Form Field on an onChange event
&lt;/h3&gt;

&lt;p&gt;In this example, each form field will have its own error message. So to make updating the state of each error message cleaner, an object was created to hold the values of error messages for all form fields with a useReducer hook to manage its state.&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;//INITIAL VALUE OF ALL ERROR MESSAGES IN THE FORM&lt;/span&gt;
&lt;span class="c1"&gt;//Each property denotes an error message for each form field&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialFormErrorState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;nameError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;“”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;emailError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;“”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;pwdError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;“”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;rpwdError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&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;reducer&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;action&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&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="nx"&gt;action&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="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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;initialFormErrorState&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;reducer&lt;/code&gt; function returns an updated state object according to the action passed in, in this case the name of the error message passed in.&lt;/p&gt;

&lt;p&gt;For a detailed explanation on the useReducer hook with an example to try out, feel free to check out my article on using the useReducer hook in forms.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/methmi" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F915647%2F5851d9c9-dce1-4e84-a81f-4b5ad80b0040.png" alt="methmi"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/methmi/forms-with-react-hooks-ig0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Forms with React Hooks&lt;/h2&gt;
      &lt;h3&gt;Methmi ・ Sep 9 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#hooks&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;Moving on to handling the onChange events of the form fields, a function can be created to take in the entered value and the name of the error message property that should show the error message (to be used by the &lt;code&gt;dispatch&lt;/code&gt; function of the useReducer hook).&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;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorFieldName&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;setUserData&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currentData&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;currentData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="nx"&gt;e&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;value&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;const&lt;/span&gt; &lt;span class="nx"&gt;propertySchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="nx"&gt;objectSchema&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;propertySchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="nx"&gt;e&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;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;errorFieldName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;errorFieldName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;details&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="nx"&gt;message&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;Line 2 to line 7 updates the state of the &lt;code&gt;userData&lt;/code&gt; object with the form field’s input. For simplicity, each form form field’s id is named its corresponding property on the &lt;code&gt;userData&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;propertySchema&lt;/code&gt; on line 8 is the object that holds the schema of the form field that’s calling the &lt;code&gt;handleChange&lt;/code&gt; function. The object &lt;code&gt;objectSchema&lt;/code&gt; contained properties that were named after each form fields id, therefore, to call a fields respective schema and to convert it into a Joi object, &lt;code&gt;Joi.object({[e.target.id] :objectSchema[e.target.id],})&lt;/code&gt; is used and the resulting schema object is stored in &lt;code&gt;propertySchema&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, the input data is converted to an object and validated against the schema in &lt;code&gt;propertySchema&lt;/code&gt; with &lt;code&gt;.validate()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This returns an object with a property called &lt;code&gt;error&lt;/code&gt;, this property contains useful values like the error type (useful when creating custom messages) and the error message.&lt;/p&gt;

&lt;p&gt;But, if the &lt;code&gt;error&lt;/code&gt; property is not present in &lt;code&gt;result&lt;/code&gt;, a validation error has not occurred, which is what we are checking in line 13.&lt;/p&gt;

&lt;p&gt;If a &lt;code&gt;error&lt;/code&gt; is present, the dispatch function is invoked with the name of the form error object’s field that should be updated in &lt;code&gt;name&lt;/code&gt;, and the error message that it should be updated to in &lt;code&gt;value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will make more sense when we look at how &lt;code&gt;handleChange&lt;/code&gt; is called in a form field. Given below is how the form field ‘Name’ calls &lt;code&gt;handleChange&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextField&lt;/span&gt;
   &lt;span class="c1"&gt;//TextField component properties&lt;/span&gt;
   &lt;span class="p"&gt;...&lt;/span&gt;
   &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleChange&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="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;nameError&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
   &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userData&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;handleChange&lt;/code&gt; accepts the value of the field as the first parameter and then the name of the respective error object’s field that the &lt;code&gt;dispatch&lt;/code&gt; function in &lt;code&gt;handleChange&lt;/code&gt; is supposed to update, &lt;code&gt;nameError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The object, &lt;code&gt;initialFormErrorState&lt;/code&gt; had one property for each form field’s error message. In this case, any validation error in the ‘Name’ field will change the &lt;code&gt;nameError&lt;/code&gt; property of &lt;code&gt;initialFormErrorState&lt;/code&gt; which will in turn be displayed in the respective alert box under the form field.&lt;/p&gt;

&lt;p&gt;Here’s a look at the finished form:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yu2kmbc7vydotsh6lar.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yu2kmbc7vydotsh6lar.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope this simple example helped show how joyful validation with Joi can be. 😊&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Till next time, happy coding!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Happy emoji vector created by freepik - &lt;a href="http://www.freepik.com" rel="noopener noreferrer"&gt;www.freepik.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>validation</category>
      <category>joi</category>
    </item>
    <item>
      <title>Making life a breeze, with Git</title>
      <dc:creator>Methmi</dc:creator>
      <pubDate>Fri, 16 Sep 2022 04:40:43 +0000</pubDate>
      <link>https://dev.to/methmi/making-life-a-breeze-with-git-3mm0</link>
      <guid>https://dev.to/methmi/making-life-a-breeze-with-git-3mm0</guid>
      <description>&lt;p&gt;Simply put,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Git is a distributed version control system.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Breaking this down shows the essence of Git:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control System&lt;/strong&gt; : Git can be used to track and store content stored in repositories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version Control System&lt;/strong&gt; : A history of all changes made to the content is stored. Also, Git allows multiple users to change content parallelly and keep things clean by separating work into branches&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distributed Version Control System&lt;/strong&gt; : Machines using a Git repository have a local copy of the repository stored and the repository is stored by remotely on a server by Git as well.&lt;/p&gt;

&lt;p&gt;To sum up, Git can be used anywhere content will be changed constantly and where it will be helpful to keep track of changes made so that content can be reverted to how it was at a certain point in its history.&lt;/p&gt;

&lt;p&gt;These features along with other features such as branching, to run multiple projects with the same base, parallelly, makes Git a very useful tool for storing and updating code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Git repository
&lt;/h2&gt;

&lt;p&gt;A repository is where all your code (or any other content) will live. It can start off as an ordinary folder or folder structure and then be converted into a smart Git repository.&lt;/p&gt;

&lt;p&gt;For this example, we will assume that an empty folder called ‘my-code-base’ has been created and a terminal window is opened up and the ‘cd’ command is used to navigate into the folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd my-code-base

git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;git init&lt;/code&gt; command turns the folder into a local repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Staging and Committing
&lt;/h2&gt;

&lt;p&gt;Assuming that a plain text file called ‘dummy-file.txt’ is added to the folder, let’s stage it, and then commit it.&lt;/p&gt;

&lt;p&gt;Staging is preparing a file (or a change in a file) to be put into a change called a commit.&lt;/p&gt;

&lt;p&gt;Staging is required before every commit, this is how the file 'dummy-file.txt' will be staged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add dummy-file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To stage multiple files at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add dummy-file.txt dummy-file2.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or to stage all files into staging area:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Committing involves registering all files currently in the staging area as a change to the repository, including a commit message describing the changes made.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m "Dummy data added to the file"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-m&lt;/code&gt; indicates that the following string wrapped in &lt;code&gt;" "&lt;/code&gt; is a commit message. If this is omitted the user is prompted to enter a commit message after running this command.&lt;/p&gt;

&lt;p&gt;Another commit option is &lt;code&gt;-a&lt;/code&gt; which automatically stages all modified files to be committed. However, this will only automatically stage files that have already been committed to the repository. For example, if &lt;code&gt;file1&lt;/code&gt; which has been committed in a previous commit is modified and &lt;code&gt;file2&lt;/code&gt; is a newly added file which has not been committed, the &lt;code&gt;-a&lt;/code&gt; option will only stage and commit &lt;code&gt;file1&lt;/code&gt; because Git is not aware of &lt;code&gt;file2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -am “New changes”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;Status of files including which files have been modified and what files are in the staging area can be revealed with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Branches
&lt;/h2&gt;

&lt;p&gt;Branches are useful for editing the same codebase parallelly without affecting another developer editing the same code. Also, if a mistake is made when editing, this will be kept separated from other branches and the main branch.&lt;/p&gt;

&lt;p&gt;A branch can be created with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch test-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and switch from the master branch (or current branch) to the created branch with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout test-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, a list of branches created can be shown with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, new changes can be staged and committed to this branch using the previous commit and stage commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge
&lt;/h2&gt;

&lt;p&gt;This is used to join a separate branch back into the active branch.&lt;/p&gt;

&lt;p&gt;First, checkout into the branch that the other branch needs to be merged into.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git merge test-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the branch test-branch will be merged into the branch you are currently on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing a remote repository
&lt;/h2&gt;

&lt;p&gt;The repository made so far exists in the local scope, this repository can be stored in remote server that can allow other developers to access and clone the repository.&lt;/p&gt;

&lt;p&gt;GitHub is a popular repository hosting service, and for this example the remote repository will be hosted in GitHub.&lt;/p&gt;

&lt;p&gt;After logging into a GitHub account, a new repository can be created via the menu on the top-righthand corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZrWuDMAe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/priaqot5cnp4x4me3q4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZrWuDMAe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/priaqot5cnp4x4me3q4g.png" alt="Image description" width="306" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, a name and privacy setting for the repository can be chosen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--31cFU-0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho2pzabus4hq3yqw0pzf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--31cFU-0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho2pzabus4hq3yqw0pzf.png" alt="Image description" width="538" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After setting up the repository, locate the repository’s URL on its page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5aRWJw3U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ez5p06kixszxcnpepr97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5aRWJw3U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ez5p06kixszxcnpepr97.png" alt="Image description" width="461" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, this URL can be used to form the command that points the local repository to the remote repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin [repository-URL]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Git Push
&lt;/h2&gt;

&lt;p&gt;A push involves sending changes from a local repository to its remote repository.&lt;/p&gt;

&lt;p&gt;To push changes, the following command is used&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pushes the committed changes in the master branch of the local repository to the master branch of the remote repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Pull
&lt;/h2&gt;

&lt;p&gt;A pull denotes updating the local repository with latest changes in the remote repository.&lt;/p&gt;

&lt;p&gt;Latest code of a certain branch (the master branch, in this example) of a remote repository can be pulled by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git pull origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a working copy of a repository ( Checkout repository )
&lt;/h2&gt;

&lt;p&gt;A locally stored repository repository can be cloned by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone path/to/local/repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, for a repository stored in a remote server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone &amp;lt;&amp;lt;repository-url&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that is how Git can be used to make versioning easy and clean and to make collaboration a breeze!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Till next time, happy coding!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>git</category>
    </item>
    <item>
      <title>Forms with React Hooks</title>
      <dc:creator>Methmi</dc:creator>
      <pubDate>Fri, 09 Sep 2022 06:57:35 +0000</pubDate>
      <link>https://dev.to/methmi/forms-with-react-hooks-ig0</link>
      <guid>https://dev.to/methmi/forms-with-react-hooks-ig0</guid>
      <description>&lt;h2&gt;
  
  
  React Hooks
&lt;/h2&gt;

&lt;p&gt;In a nutshell, React Hooks can be described as ;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Functions that let you “hook into” React state and lifecycle features from function components. — &lt;a href="https://reactjs.org/docs/hooks-overview.html"&gt;React&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Introduced in React 16.8, a Hook (in React) is a function that keeps track of the state of a React functional component, and is used to solve the problem of only class components in React being able to access the state of the application before Hooks were introduced.&lt;/p&gt;

&lt;p&gt;And &lt;strong&gt;state&lt;/strong&gt; is how the dynamic data of a component is tracked by a component so that it can maintain the changes made to the component between renders.&lt;/p&gt;

&lt;p&gt;So, to sum up, state stores the changing data of a component, and Hooks are used to manage that state.&lt;/p&gt;

&lt;p&gt;This would mean that Hooks are essential for interactive components.&lt;/p&gt;

&lt;p&gt;To start off, let’s see how we could use react hooks to keep track of the changing state in a vital interactive web component, forms, using two &lt;a href="https://mui.com/"&gt;Material UI&lt;/a&gt; components to demonstrate, a select and a checkbox.&lt;/p&gt;

&lt;p&gt;For the second part, a few more components will be added to the form to demonstrate how the code can be cleaned. And for the sake of an interesting example, the final form tries to figure out which type of dog matches a user’s personality. 🤭&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling form state
&lt;/h2&gt;

&lt;p&gt;Handling a form’s state would mean specifying what will happen when a user changes an input field in the form, and keeping track of each change the user makes in the form.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Select component
&lt;/h3&gt;

&lt;p&gt;To start, here’s the basic structure of Material UI’s Select component.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;On a typical weekend, I'll be&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;labelId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;select-outlined-label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MenuItem&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&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;Bungee&lt;/span&gt; &lt;span class="nx"&gt;jumping&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;had&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MenuItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MenuItem&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Taking&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;calm&lt;/span&gt; &lt;span class="nx"&gt;walk&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MenuItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MenuItem&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&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;Taking&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;well&lt;/span&gt; &lt;span class="nx"&gt;deserved&lt;/span&gt; &lt;span class="nx"&gt;nap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MenuItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Select&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;&amp;lt;MenuItem&amp;gt;&lt;/code&gt; tag denotes an item in the select’s drop down list. And the value property on the &lt;code&gt;&amp;lt;MenuItem&amp;gt;&lt;/code&gt; tag holds the data that identifies each option. The &lt;code&gt;value&lt;/code&gt; property of the &lt;code&gt;&amp;lt;Select&amp;gt;&lt;/code&gt; tag will be the value of the option picked by the user, and will therefore be used to display the option picked by the user.&lt;/p&gt;

&lt;p&gt;Therefore, the data in the &lt;code&gt;value&lt;/code&gt; property of the &lt;code&gt;&amp;lt;Select&amp;gt;&lt;/code&gt; tag is what should be tracked as state, since the user selecting an option is the dynamic (changing) aspect of this form input field. Which means a variable to hold state should be passed into the &lt;code&gt;value&lt;/code&gt; property of the &lt;code&gt;&amp;lt;Select&amp;gt;&lt;/code&gt; tag. And the &lt;code&gt;onChange&lt;/code&gt; property defines what will be done when the Select input field is changed. In this case, we would want it to update the data stored in the value property of the &lt;code&gt;&amp;lt;Select&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  The useState Hook
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useState()&lt;/code&gt; Hook is used to create a state holder required by the Select.&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;activeScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveScore&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To break down that statement;&lt;/p&gt;

&lt;p&gt;The argument passed into &lt;code&gt;useState()&lt;/code&gt; is what the initial value of the state holder created will be. In this case the initial value would be 3. This means that the Select will initially display the menu item with a &lt;code&gt;value&lt;/code&gt; property of 3 (&lt;code&gt;value={3}&lt;/code&gt;) as picked by the Select component.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[activeScore, setActiveScore]&lt;/code&gt; uses array de-structuring here. The &lt;code&gt;useState()&lt;/code&gt; function returns an array of two items: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The state holder&lt;/li&gt;
&lt;li&gt;A reference to a function that is used to update the value held in the state holder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When array de-structuring is used here, the first element of the array returned (state holder) is stored in the variable &lt;code&gt;activeScore&lt;/code&gt; and the second element of the array (a reference to update function) is stored in &lt;code&gt;setActiveScore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The variable names that are used when de-structuring the array could be anything, in this case they are named &lt;code&gt;activeScore&lt;/code&gt; and &lt;code&gt;setActiveScore&lt;/code&gt; to represent the state value they will be referring to.&lt;/p&gt;

&lt;p&gt;The previous code for Select had data for its &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;onChange&lt;/code&gt; property missing.&lt;/p&gt;

&lt;p&gt;So, to pass the de-structured array to each prop, the &lt;code&gt;value&lt;/code&gt; property will receive &lt;code&gt;activeScore&lt;/code&gt; since it holds the value selected by the user for active score. To ensure that the &lt;code&gt;activeScore&lt;/code&gt; will preserved when the page re-renders, the &lt;code&gt;onChange&lt;/code&gt; property will receive &lt;code&gt;setActiveScore&lt;/code&gt; because each time the user changes the value of Select, the new value will have to be updated in the &lt;code&gt;activeScore&lt;/code&gt; state holder, and &lt;code&gt;setActiveScore&lt;/code&gt; contains the reference to the function that does that.&lt;/p&gt;

&lt;p&gt;But the each time the field is changed, an event object will be returned, which will contain the value of the value property of the &lt;code&gt;&amp;lt;MenuItem&amp;gt;&lt;/code&gt; that the user has picked from the Select. This is the value that should be passed into &lt;code&gt;setActiveScore&lt;/code&gt; and to extract this value, the &lt;code&gt;onChange&lt;/code&gt; will be defined as &lt;code&gt;(e) =&amp;gt; setActiveScore(e.target.value)&lt;/code&gt; where &lt;code&gt;e&lt;/code&gt; is the variable defined to store the event object received.&lt;/p&gt;

&lt;p&gt;And the completed Select component with all its properties set to display and update the state, will look 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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;activeScore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setActiveScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;On a typical weekend, I'll be&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;labelId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;select-outlined-label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MenuItem&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&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;Bungee&lt;/span&gt; &lt;span class="nx"&gt;jumping&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;had&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MenuItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MenuItem&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Taking&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;calm&lt;/span&gt; &lt;span class="nx"&gt;walk&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MenuItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MenuItem&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&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;Taking&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;well&lt;/span&gt; &lt;span class="nx"&gt;deserved&lt;/span&gt; &lt;span class="nx"&gt;nap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MenuItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Select&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the Select component rendered like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BCsNRKqc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3icx9uu3indgwskzhr98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BCsNRKqc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3icx9uu3indgwskzhr98.png" alt="The option to which activeScore is initialized to is displayed initially" width="330" height="86"&gt;&lt;/a&gt;&lt;/p&gt;
The option to which activeScore is initialized to is displayed initially



&lt;h3&gt;
  
  
  A Checkbox component
&lt;/h3&gt;

&lt;p&gt;The only difference in this component is that it simply stores a Boolean value, therefore its state will be initialized to a true or false value unlike the previous state holders which were initialized by numbers.&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;agree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAgree&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And used in the Checkbox component in the following way;&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormControlLabel&lt;/span&gt;
&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&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;I agree to not be offended by the results as this is just an &lt;/span&gt;&lt;span class="dl"&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;example and not at all an accurate representation of me or the dog
😁&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;control&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;Checkbox&lt;/span&gt;
  &lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;agree&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setAgree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To demonstrate how state is dynamically updated, let’s enable the submit button only when the check box is checked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2MQuhpNX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jllwhc5u92cqp3auz8yo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2MQuhpNX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jllwhc5u92cqp3auz8yo.png" alt="Image of enabled button" width="770" height="67"&gt;&lt;/a&gt;&lt;/p&gt;
Box checked so button is enabled




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8VkjEIgX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mo9vy142gcw084exrqpd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8VkjEIgX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mo9vy142gcw084exrqpd.png" alt="Image of enabled button" width="770" height="59"&gt;&lt;/a&gt;&lt;/p&gt;
Box unchecked so button is disabled



&lt;p&gt;This can be done easily by passing the &lt;code&gt;agree&lt;/code&gt; state holder manipulated by the checkbox to the &lt;code&gt;disabled&lt;/code&gt; property of the Button component. When &lt;code&gt;agree&lt;/code&gt; is true, &lt;code&gt;disabled&lt;/code&gt; should be false. The logical NOT operator &lt;strong&gt;!&lt;/strong&gt; is used with &lt;code&gt;agree&lt;/code&gt; to get the logical complement (the opposite Boolean value) of &lt;code&gt;agree&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;
&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;agree&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contained&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;displayResults&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="cm"&gt;/* displayResults is the function that determines the result from the user input */&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;Show&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now with our form in place, we will be moving to the final piece of the page, the result display.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--llTae_lN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7x2o982aorpw9fso93i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--llTae_lN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7x2o982aorpw9fso93i.png" alt="Image of Result shown below the button" width="770" height="105"&gt;&lt;/a&gt;&lt;/p&gt;
Result shown below the button



&lt;p&gt;The component is nothing more than text below the button, but it will have to display a different result for each different combination of answers according to the &lt;code&gt;displayResults&lt;/code&gt; function. &lt;br&gt;
Sounds familiar? Yup, we will be tracking state here as well.&lt;/p&gt;

&lt;p&gt;First the state holder for the result, with the initial result set to nothing:&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResult&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="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;Next, a &lt;a href="https://mui.com/material-ui/react-typography/"&gt;Typography&lt;/a&gt; component to show the result and update each time &lt;code&gt;result&lt;/code&gt; changes.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Typography&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h4&lt;/span&gt;&lt;span class="dl"&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;result&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`It's the &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;``&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Typography&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ternary operator &lt;code&gt;(&amp;lt;variable&amp;gt; ? &amp;lt;if true&amp;gt; : &amp;lt;if false&amp;gt;)&lt;/code&gt; used here says that if &lt;code&gt;result&lt;/code&gt; is true, the sentence is shown, else an empty string is visible. The sentence itself is a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;template literal&lt;/a&gt; that displays the value stored inside &lt;code&gt;result&lt;/code&gt; with &lt;code&gt;${result}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the submit button is clicked, the &lt;code&gt;displayResults&lt;/code&gt; function is called and it changes result each time, by calling &lt;code&gt;setResult&lt;/code&gt; within &lt;code&gt;displayResults&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;displayResults&lt;/code&gt; function of this example is just a function that categorizes a user to a personality based on the scores chosen and can be replaced by any function that processes form data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning up the Hooks
&lt;/h2&gt;

&lt;p&gt;A few more components like a slider and a radio group were added to this form to show how a lot of useState hooks could be a problem. &lt;/p&gt;

&lt;p&gt;With a couple more input fields, the useState hooks now look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2ZQKWF1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlfv5dupakb7pv3ev1a3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2ZQKWF1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlfv5dupakb7pv3ev1a3.png" alt="Image description" width="453" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And having a separate useState hook for each input won’t look any better when the number of input fields increase.&lt;br&gt;
Enter the useReducer hook.&lt;/p&gt;
&lt;h3&gt;
  
  
  The useReducer Hook
&lt;/h3&gt;

&lt;p&gt;This hook can be used alternative to the useState hook when managing complex state logic in a React component.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useReducer()&lt;/code&gt; Hook will be given a reducer function and an initial state, the Hook returns an array with the current state and a function to pass an action to and invoke, in this case when an input field changes. The current state object and dispatch function are de-structured and stored in &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;dispatch&lt;/code&gt; respectively.&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="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="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialFormState&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;initialFormState&lt;/code&gt; is the original state of the form and will there for have all the values passed into the &lt;code&gt;useState()&lt;/code&gt; Hooks earlier, combined as one object.&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;initialFormState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;alertScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;friendlyScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;activeScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;agree&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;reducer&lt;/code&gt; function passed into &lt;code&gt;useReducer()&lt;/code&gt; returns some data, in this case an updated state object, and it will update the state based on the passed in action’s type. So, the reducer accepts a state (the current state) and an action.&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;reducer&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;action&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;switch&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;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;activeScore&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;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;activeScore&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;value&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alertScore&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;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alertScore&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;value&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;friendlyScore&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;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;friendlyScore&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;value&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agree&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;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;agree&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;value&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&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;A switch case block inside determines how the state is updated, based on the &lt;code&gt;type&lt;/code&gt; property of the &lt;code&gt;action&lt;/code&gt; passed in.&lt;/p&gt;

&lt;p&gt;So, if an action of, for example, &lt;code&gt;activeScore&lt;/code&gt; is given, the &lt;code&gt;activeScore&lt;/code&gt; property of the current state state is updated with the &lt;code&gt;value&lt;/code&gt; property of the action &lt;code&gt;action.value&lt;/code&gt; and a new state is returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&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="na"&gt;activeScore&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;value&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, to &lt;strong&gt;only&lt;/strong&gt; update the required property of the &lt;code&gt;state&lt;/code&gt; object, the state is spread with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax"&gt;spread operator&lt;/a&gt; &lt;code&gt;...&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;The syntax expands the current object (&lt;code&gt;state&lt;/code&gt;) so that all its current elements are included and the required element (&lt;code&gt;activeScore&lt;/code&gt; in this case) is updated while preserving the original value of the other elements.&lt;/p&gt;

&lt;p&gt;To capture user input, the &lt;code&gt;reducer&lt;/code&gt; function is accessed by invoking the dispatch function returned from the &lt;code&gt;useReducer()&lt;/code&gt;, in the &lt;code&gt;onChange&lt;/code&gt; event of an input field.&lt;/p&gt;

&lt;p&gt;Here’s the opening tag of the Select component doing that:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;activeScore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="c1"&gt;//more component properties . . . &lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the value of &lt;code&gt;&amp;lt;Select&amp;gt;&lt;/code&gt; is now set to &lt;code&gt;state.activeScore&lt;/code&gt; since we’re accessing the state of &lt;code&gt;activeScore&lt;/code&gt; from the property stored in the current state object, &lt;code&gt;state&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplifying the reducer function
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useReducer()&lt;/code&gt; implemented now works. But, a case statement is needed for each action type (i.e.: each input field) that exists, which would be bad news for large forms.&lt;/p&gt;

&lt;p&gt;However, notice how all the action types have the same name as the state element it controls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NXmH3v1B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87uwx5zpveyolrxhzwwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NXmH3v1B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87uwx5zpveyolrxhzwwb.png" alt="Image of action types having the same name as the state element it controls" width="459" height="64"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore, the reducer can be simplified to update the state element that &lt;em&gt;has the same name&lt;/em&gt; as the &lt;code&gt;action.type&lt;/code&gt; passed into it.&lt;/p&gt;

&lt;p&gt;And the entire reducer function can be simply written as:&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;reducer&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;action&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;return&lt;/span&gt; &lt;span class="p"&gt;{&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="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;type&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;value&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;where the &lt;code&gt;[action.type]&lt;/code&gt; is the required property to updated in the state.&lt;/p&gt;

&lt;p&gt;And the onChange functions will be updated to:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;activeScore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&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="s2"&gt;activeScore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="c1"&gt;//more component properties . . .&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dispatch call from onChange could be simplified further too.&lt;/p&gt;

&lt;p&gt;Right now, the object passed into dispatch() is hardcoded for each input component.&lt;/p&gt;

&lt;p&gt;But if we could retrieve the name and value both from the target property of event e itself, the dispatch() function would only require e.target to be passed into it. This is possible by giving a name property to .&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;
&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;activeScore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;activeScore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="c1"&gt;//more component properties . . .&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, both &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; can be extracted from &lt;code&gt;e.target&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And to make the &lt;code&gt;reducer&lt;/code&gt; function extract &lt;code&gt;name&lt;/code&gt; from the action (&lt;code&gt;e.target&lt;/code&gt;) passed in, the reducer will be updated the following way:&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;reducer&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;action&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;return&lt;/span&gt; &lt;span class="p"&gt;{&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="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;name&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;value&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;so that name is extracted from &lt;code&gt;action&lt;/code&gt; instead of &lt;code&gt;type&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And that’s how the :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; Hook can be set up to manage state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;useReducer&lt;/code&gt; Hook can be used to manage large state objects, as an alternative to the &lt;code&gt;useState&lt;/code&gt; Hook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;reducer&lt;/code&gt; function of the &lt;code&gt;useState&lt;/code&gt; Hook can be cleaned up a bit 😊.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Hope this example helped shed some light on React Hooks and how they are used in interactive web components to manage their state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Till next time, happy coding!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>hooks</category>
    </item>
    <item>
      <title>Giddy-up with GitHub Actions</title>
      <dc:creator>Methmi</dc:creator>
      <pubDate>Fri, 02 Sep 2022 05:22:56 +0000</pubDate>
      <link>https://dev.to/methmi/giddy-up-with-github-actions-18ml</link>
      <guid>https://dev.to/methmi/giddy-up-with-github-actions-18ml</guid>
      <description>&lt;p&gt;Explore GitHub Actions with a CV generator ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GitHub Actions?
&lt;/h2&gt;

&lt;p&gt;GitHub Actions is a platform that can be used to &lt;a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions"&gt;automate a build, test and deployment pipeline&lt;/a&gt;. This platform has several components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Events:&lt;/strong&gt; Something that happens in a GitHub repository (such as pushing to a branch, opening an issue or a pull request)that can trigger the start of a workflow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflows:&lt;/strong&gt; An automated process that is configured to run once a trigger is fulfilled. They consist of one or more jobs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Jobs:&lt;/strong&gt; A job consists of a series of steps that run in the order they are written, one after the other in the same runner. Multiple jobs could run parallelly. Each step in a job could be a shell script or an action.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Actions:&lt;/strong&gt; This is what happens in a workflow (a single step). They perform tasks that are complex and repetitive, therefore they can reduce repeated code in your workflow file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Runners:&lt;/strong&gt; A runner is a server that runs the triggered workflow, and each runner will run a single job at a time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This article focuses on a project that generates a CV using a python script that converts data in JSON files to a format for a LaTeX CV template, run automatically by a GitHub Actions workflow that also converts the generated .tex file to a CV in PDF format when changes are pushed to the &lt;code&gt;master&lt;/code&gt; branch.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/methminug"&gt;
        methminug
      &lt;/a&gt; / &lt;a href="https://github.com/methminug/CV-Generator"&gt;
        CV-Generator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Edit a simple JSON file to generate an elegantly formatted CV ✨
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
CV-Generator 🖨️
&lt;/h1&gt;
&lt;p&gt;A python script that converts data in &lt;b&gt;JSON files to a .tex format&lt;/b&gt; for a &lt;a href="https://github.com/posquit0/Awesome-CV"&gt;LaTex CV template&lt;/a&gt;, run automatically by a GitHub Actions workflow that also converts the generated .tex file to a CV in PDF format when changes are pushed to the &lt;code&gt;master&lt;/code&gt; branch.&lt;/p&gt;
&lt;h2&gt;
But why? 🤔
&lt;/h2&gt;
&lt;p&gt;LaTex templates are great for creating well formatted documents. &lt;br&gt;
However, some may find it hard to work with the TeX type setting system used in LaTex, and may even feel that its not worth the time spent editing a complex looking .tex file to create a fairly simple looking CV.&lt;/p&gt;
&lt;p&gt;And, that's what this script tries to fix.&lt;/p&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;A user &lt;b&gt; edits the simple JSON files &lt;/b&gt; in the &lt;code&gt;sections&lt;/code&gt; folder that correspond to each section in the CV template. &lt;br&gt;
Here's an example from the &lt;code&gt;experience.json&lt;/code&gt; file for the Work Experience section of the CV.&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;{
    "title":"Work Experience"
    "sectionname":"cventries",&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/methminug/CV-Generator"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This project is not purely made from GitHub Actions workflows, but they are the core of what will be used to eventually generate the CV. In summary, the final workflow file will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be triggered to generate a new CV when changes are made to data in JSON files.&lt;/li&gt;
&lt;li&gt;Run a Docker container that will run a Python script to convert data from the JSON files to a LaTeX template, then convert the file from the template to a PDF.&lt;/li&gt;
&lt;li&gt;Commit the newly created PDF to the repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a bit of background, &lt;a href="https://www.latex-project.org/"&gt;LaTeX&lt;/a&gt; is a software system widely used to create academic documents, allowing creators to focus on the content while LaTeX handles the formatting. Templates for LaTeX documents make things even faster, making it an ideal option for creating a document like a CV where a more time and effort must be put into the content rather than the format.&lt;/p&gt;

&lt;p&gt;The LaTeX template used here is Awesome CV by posquit0, and can be found at: &lt;a href="https://github.com/posquit0/Awesome-CV"&gt;github.com/posquit0/Awesome-CV&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for this cool template!&lt;/p&gt;




&lt;p&gt;As this article focuses on actions and workflow files, the content of the Python scripts will not be discussed here, but in short, they replace placeholder text in the LaTeX template with data from JSON files that contain actual data for the CV.&lt;/p&gt;

&lt;p&gt;So, let’s jump into the workflow file!&lt;/p&gt;

&lt;h3&gt;
  
  
  Parts of a workflow file
&lt;/h3&gt;

&lt;p&gt;A workflow is a file written in YAML syntax.&lt;/p&gt;

&lt;p&gt;GitHub Actions recognizes workflow files to run by checking specifically for a directory named &lt;code&gt;.github/workflows&lt;/code&gt; in the branch that you want the workflow to be triggered from (the &lt;code&gt;master&lt;/code&gt; branch in this case).&lt;/p&gt;

&lt;p&gt;The main parts of a workflow file are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Name (optional)&lt;/li&gt;
&lt;li&gt;Trigger&lt;/li&gt;
&lt;li&gt;Jobs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The name given to a workflow is what will appear when the workflow is shown in the Actions tab of the GitHub repository. The name is configured at the top of the file by the statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update CV&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The trigger is what will cause this workflow to start running. A trigger can be multiple events or a single event. The following statement configures the workflow to run when a push is made to any branch or when someone forks the repository.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;fork&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, comes the jobs sections which group together all the jobs that will run in the workflow.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;&amp;lt;Name of first job&amp;gt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s"&gt;. . .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Building the workflow file
&lt;/h3&gt;

&lt;p&gt;The gist of this generator is that when data in a set of JSON files in the &lt;code&gt;master&lt;/code&gt; branch is updated, a new CV should be created according to the updated data in the files.&lt;/p&gt;

&lt;p&gt;Therefore, we would want the CV generating workflow to run each time any changes are pushed to the &lt;code&gt;master&lt;/code&gt; branch of the repository.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update CV&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As explained previously, the &lt;code&gt;on:&lt;/code&gt; section defines the trigger event, and the trigger event of this workflow is a push to a branch, so &lt;code&gt;push:&lt;/code&gt; is used.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;push:&lt;/code&gt; event has a filter called &lt;code&gt;branches:&lt;/code&gt; which allows us to configure the workflow to be triggered only when there is a push event made to a specific branch or branches. In this case, the workflow will only start when a push is made to the &lt;code&gt;master&lt;/code&gt; branch of the repository.&lt;/p&gt;

&lt;p&gt;Moving onto the &lt;code&gt;jobs:&lt;/code&gt; section of the workflow file, our goals are to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checkout the current branch.&lt;/li&gt;
&lt;li&gt;Generate a CV.&lt;/li&gt;
&lt;li&gt;Commit the changes.&lt;/li&gt;
&lt;li&gt;Push the changes to master branch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;s these steps have to take place one after the other, they can all be defined as consecutive steps of one job. Each new step will be marked with a hyphen (&lt;code&gt;-&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To set the environment for running this job, the following lines under the &lt;code&gt;jobs:&lt;/code&gt; section will be added to the file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update CV&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;update_cv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;. . .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, &lt;code&gt;update_cv&lt;/code&gt; is the name given to the job that will run the previously mentioned steps. Note that &lt;code&gt;Update CV&lt;/code&gt; is the name of the &lt;strong&gt;workflow&lt;/strong&gt; that runs a &lt;strong&gt;job&lt;/strong&gt; named &lt;code&gt;update_cv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;update_cv&lt;/code&gt; job is configured to run on the latest version of an Ubuntu Linux runner as defined by &lt;code&gt;runs-on:&lt;/code&gt; . This job will run on a virtual machine hosted by GitHub.&lt;/p&gt;

&lt;p&gt;Then, the steps will be added in the order of execution under &lt;code&gt;steps:&lt;/code&gt; .&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Checkout current branch
&lt;/h4&gt;

&lt;p&gt;This step is necessary to make the contents repository accessible to the workflow. This is important as we will be using a private action in this repository later on in this job. Therefore a checkout action should be used any time a workflow will run against the repository’s code.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;. . .&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;update_cv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The step used to checkout the repository uses the action, Checkout V3, from the GitHub Marketplace, and uses the &lt;code&gt;uses:&lt;/code&gt; keyword to define the action that will be used in this specific step.&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Generating the CV
&lt;/h4&gt;

&lt;p&gt;Next is the step that runs the script to generate the CV and convert it to a PDF, this will be run in a Docker container, so first we will be building a docker container action to be executed in this step. This action will be defined in a separate YAML file in the repository, named &lt;code&gt;generate-cv.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h5&gt;
  
  
  The Docker container action
&lt;/h5&gt;

&lt;p&gt;To start the Docker container and run the actions code, a Docker image should be specified.&lt;/p&gt;

&lt;p&gt;The docker image can be specified in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;As a Dockerfile in the repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using an image from the public Docker registry.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this example, we will be using a Dockerfile created in the root directory of the repository.&lt;/p&gt;

&lt;p&gt;Therefore, the action in the &lt;code&gt;generate-cv.yaml&lt;/code&gt; file (which is also in the root directory) will be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Generate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CV'&lt;/span&gt;
&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;docker'&lt;/span&gt;
   &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Dockerfile'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;According to the code, this action will be run using &lt;code&gt;‘docker’&lt;/code&gt; since it is a Docker action, and an image will be built from &lt;code&gt;‘Dockerfile’&lt;/code&gt; and the commands will be run in a new container using this image.&lt;/p&gt;

&lt;p&gt;Now, the Docker container action created can be used as a private action in the next step of the &lt;code&gt;update_cv&lt;/code&gt; job of our workflow file.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;. . .&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;update_cv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate CV&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The private action’s name &lt;code&gt;Generate CV&lt;/code&gt; is given to the &lt;code&gt;name:&lt;/code&gt; keyword in this step. Since this step uses an action in the root directory, a path of &lt;code&gt;./&lt;/code&gt; is given to the &lt;code&gt;uses:&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;This step will run the Python script that would update the LaTeX template file, create a .tex file from the updated LaTeX template file and finally create a PDF file of the CV from the .tex file.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Commit the changes
&lt;/h4&gt;

&lt;p&gt;Next, the newly created PDF file and updates to the LaTeX template file should be committed.&lt;/p&gt;

&lt;p&gt;This can be done by via git commands.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;. . .&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;update_cv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate CV&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit generated PDF&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
           &lt;span class="s"&gt;git config --local user.email "action@github.com"&lt;/span&gt;
           &lt;span class="s"&gt;git config --local user.name "github-actions"&lt;/span&gt;
           &lt;span class="s"&gt;git add --all&lt;/span&gt;
           &lt;span class="s"&gt;git commit -m "CV updated via GH Actions" -a&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The first two commands configure the GitHub Actions bot to commit to the repository.&lt;/p&gt;

&lt;p&gt;Then, all the changes are committed by the bot under a new commit with the commit message &lt;code&gt;"CV updated via GH Actions"&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;These commands are executed using &lt;code&gt;bash&lt;/code&gt; which is the default shell on non-Windows platforms.&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Push the changes to branch
&lt;/h4&gt;

&lt;p&gt;Finally, the commit made should be pushed to the master branch.&lt;/p&gt;

&lt;p&gt;The third party action &lt;a href="https://github.com/marketplace/actions/github-push"&gt;GitHub Push&lt;/a&gt; from the GitHub Marketplace will be used for this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;. . .&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;update_cv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate CV&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit generated PDF&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
           &lt;span class="s"&gt;git config --local user.email "action@github.com"&lt;/span&gt;
           &lt;span class="s"&gt;git config --local user.name "github-actions"&lt;/span&gt;
           &lt;span class="s"&gt;git add --all&lt;/span&gt;
           &lt;span class="s"&gt;git commit -m "CV updated via GH Actions" -a&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push changes&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ad-m/github-push-action@master&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;github_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The keyword &lt;code&gt;with:&lt;/code&gt; groups the inputs sent to the GitHub Push action. As a repository has not been given as input, the changes will be pushed to the &lt;code&gt;master&lt;/code&gt; branch of the current repository.&lt;/p&gt;

&lt;p&gt;The input for &lt;code&gt;github_token&lt;/code&gt; used here is a unique &lt;a href="https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow"&gt;GITHUB_TOKEN secret&lt;/a&gt; that GitHub automatically creates at the start of each workflow run, which can be used to authenticate on behalf of GitHub Actions.&lt;/p&gt;

&lt;p&gt;A repository scoped &lt;a href="https://medium.com/sliitwif/giddy-up-with-github-actions-2d3b74c1b6fa"&gt;personal access token&lt;/a&gt; could also be used as the &lt;code&gt;github_token&lt;/code&gt; input instead.&lt;/p&gt;



&lt;p&gt;And that concludes our job for our GitHub Actions workflow!&lt;/p&gt;

&lt;p&gt;The complete codebase can be found in the repository linked below, so feel free to &lt;a href="https://docs.github.com/en/get-started/quickstart/fork-a-repo"&gt;fork&lt;/a&gt; it, make some changes to the JSON files in the &lt;code&gt;/sections&lt;/code&gt; directory and watch this workflow spring to action!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/methminug"&gt;
        methminug
      &lt;/a&gt; / &lt;a href="https://github.com/methminug/CV-Generator"&gt;
        CV-Generator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Edit a simple JSON file to generate an elegantly formatted CV ✨
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
CV-Generator 🖨️
&lt;/h1&gt;
&lt;p&gt;A python script that converts data in &lt;b&gt;JSON files to a .tex format&lt;/b&gt; for a &lt;a href="https://github.com/posquit0/Awesome-CV"&gt;LaTex CV template&lt;/a&gt;, run automatically by a GitHub Actions workflow that also converts the generated .tex file to a CV in PDF format when changes are pushed to the &lt;code&gt;master&lt;/code&gt; branch.&lt;/p&gt;
&lt;h2&gt;
But why? 🤔
&lt;/h2&gt;
&lt;p&gt;LaTex templates are great for creating well formatted documents. &lt;br&gt;
However, some may find it hard to work with the TeX type setting system used in LaTex, and may even feel that its not worth the time spent editing a complex looking .tex file to create a fairly simple looking CV.&lt;/p&gt;
&lt;p&gt;And, that's what this script tries to fix.&lt;/p&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;A user &lt;b&gt; edits the simple JSON files &lt;/b&gt; in the &lt;code&gt;sections&lt;/code&gt; folder that correspond to each section in the CV template. &lt;br&gt;
Here's an example from the &lt;code&gt;experience.json&lt;/code&gt; file for the Work Experience section of the CV.&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;{
    "title":"Work Experience"
    "sectionname":"cventries",&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/methminug/CV-Generator"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Till next time, happy coding!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Dog cartoon vector created by catalyststuff — &lt;a href="https://www.freepik.com/vectors/dog-cartoon"&gt;www.freepik.com&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Rhyme Ping Pong</title>
      <dc:creator>Methmi</dc:creator>
      <pubDate>Mon, 29 Aug 2022 22:04:51 +0000</pubDate>
      <link>https://dev.to/methmi/rhyme-ping-pong-2lm8</link>
      <guid>https://dev.to/methmi/rhyme-ping-pong-2lm8</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;Play ping pong, but with rhymes! 🏓&lt;/p&gt;

&lt;p&gt;Go back and forth with rhymes instead of a ping pong ball and see if you can have the last word! The application uses inputs of previous players to come up with its rhymes as a response to yours.&lt;/p&gt;

&lt;p&gt;The rhythm and flow of most poems, sometimes felt like a game of ping pong to me, which became the inspiration behind the simple game, Rhyme Ping Pong. 😁&lt;/p&gt;

&lt;p&gt;This application tries to come up with a rhyme for each sentence entered and simultaneously builds up its knowledge by storing each unique sentence entered so that it can be used as a rhyme in the future. &lt;/p&gt;

&lt;h4&gt;
  
  
  How it's built
&lt;/h4&gt;

&lt;p&gt;The user interface of this application was built with React and the Material UI library, and communicates through REST APIs built with the Express framework.&lt;/p&gt;

&lt;p&gt;Redis, a key value data store was used as the primary database where its modules RedisJSON and RediSearch were used to store and retrieve data respectively. &lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Wacky Wildcards&lt;/p&gt;

&lt;h3&gt;
  
  
  Video Explainer of My Project
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/h04xTe3a1wQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Language Used
&lt;/h3&gt;

&lt;p&gt;JS/TS/Node.js&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/methminug"&gt;
        methminug
      &lt;/a&gt; / &lt;a href="https://github.com/methminug/RhymePingPong"&gt;
        RhymePingPong
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Play ping pong, but with rhymes! 🏓
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Rhyme Ping Pong&lt;/h1&gt;
&lt;p&gt;Go back and forth with rhymes instead of a ping pong ball and see if you can have the last word! The application uses inputs of previous players to come up with its rhymes as a response to yours.&lt;/p&gt;
&lt;p&gt;The rhythm and flow of most poems, sometimes felt like a game of ping pong to me, which became the inspiration behind the simple game, Rhyme Ping Pong. 😁&lt;/p&gt;
&lt;p&gt;This application tries to come up with a rhyme for each sentence entered and simultaneously builds up its knowledge by storing each unique sentence entered so that it can be used as a rhyme in the future.&lt;/p&gt;
&lt;h2&gt;
Screenshots&lt;/h2&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://user-images.githubusercontent.com/62464945/187123273-d2987041-b612-459f-aa32-589d627900b3.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1LDzw8DQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/62464945/187123273-d2987041-b612-459f-aa32-589d627900b3.png" width="800"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://user-images.githubusercontent.com/62464945/187122726-c25ca4ac-5928-42bd-a6c5-4619a51c93c7.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5b33ZZpZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/62464945/187122726-c25ca4ac-5928-42bd-a6c5-4619a51c93c7.png" width="800"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://user-images.githubusercontent.com/62464945/187122739-de02145f-a01d-41a5-923e-50bd3d174fbb.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tnsBiFJT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/62464945/187122739-de02145f-a01d-41a5-923e-50bd3d174fbb.png" width="800"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
Overview video&lt;/h1&gt;
&lt;p&gt;Here's a short video that explains the project and how it uses Redis:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=h04xTe3a1wQ" rel="nofollow"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a9JtLjfn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/62464945/187299751-9a5397e3-4751-4eaa-84eb-185a7bdb3d8f.png" alt="Embed your YouTube video"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
How it works&lt;/h2&gt;
&lt;p&gt;New sentences input by the user are stored along with the word ending of the sentence’s final word, which is then used to…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/methminug/RhymePingPong"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources (Screenshots)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LTmcLzEG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xh02o61zsxok48b80lwy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LTmcLzEG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xh02o61zsxok48b80lwy.png" alt="Image description" width="880" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ut8GF4zE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpxr1ramn5ypizgs07n3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ut8GF4zE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpxr1ramn5ypizgs07n3.png" alt="Image description" width="880" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tNSGpT3H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g612u408c6i0r2bcwdpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tNSGpT3H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g612u408c6i0r2bcwdpc.png" alt="Image description" width="880" height="413"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Check out &lt;a href="https://redis.io/docs/stack/get-started/clients/#high-level-client-libraries"&gt;Redis OM&lt;/a&gt;, client libraries for working with Redis as a multi-model database.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Use &lt;a href="https://redis.info/redisinsight"&gt;RedisInsight&lt;/a&gt; to visualize your data in Redis.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Sign up for a &lt;a href="https://redis.info/try-free-dev-to"&gt;free Redis database&lt;/a&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redishackathon</category>
    </item>
    <item>
      <title>Why JavaScript Promises are awesome</title>
      <dc:creator>Methmi</dc:creator>
      <pubDate>Fri, 26 Aug 2022 04:34:00 +0000</pubDate>
      <link>https://dev.to/methmi/why-javascript-promises-are-awesome-4obk</link>
      <guid>https://dev.to/methmi/why-javascript-promises-are-awesome-4obk</guid>
      <description>&lt;h2&gt;
  
  
  What is a Promise?
&lt;/h2&gt;

&lt;p&gt;A promise, in computer science, is basically a concept that handles a value that is to be produced in the future, after an asynchronous operation completes successfully or if it does not, gracefully handles a failure.&lt;/p&gt;

&lt;p&gt;Too much jargon?&lt;/p&gt;

&lt;p&gt;Here’s a high level picture -&lt;/p&gt;

&lt;p&gt;You may lend something to a friend and trust them enough to know that you won’t have to stop whatever you were doing and wait for them to return it. You know that they will return it eventually, so, you’ll be able to go one with your life until the item (or an excuse 😅) is returned.&lt;br&gt;
Although you will act on the eventual outcome of the promise that the friend gave you, you will save that for the time the promise is actually fulfilled.&lt;/p&gt;

&lt;p&gt;This was the concept in mind when the term Promise (in computer science) was first coined in 1976.&lt;/p&gt;

&lt;p&gt;Promise concepts were popularized in the JavaScript world by the jQuery Deferred Objects, that were similar in concept to the Promise, but differed from the current specification of Promises in ECMAScript 2015.&lt;/p&gt;

&lt;p&gt;After their official acceptance into the ECMAScript 2015 spec, they are now implemented in all the latest browsers and Node, and are here to cleanup the potential muddle in callbacks and simplify the process.&lt;/p&gt;
&lt;h2&gt;
  
  
  What about Callback functions?
&lt;/h2&gt;

&lt;p&gt;Callbacks also produce values after an asynchronous operation but executing one asynchronous operation after the other requires callbacks to be called inside another callback, as shown below.&lt;/p&gt;

&lt;p&gt;The callbacks being nested deeper and deeper cause the code to expand horizontally as well, leading to an error-prone and confusing code block understandably known as ‘Callback Hell’.&lt;/p&gt;

&lt;p&gt;Promises are used to bypass this.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using Promises instead
&lt;/h2&gt;

&lt;p&gt;A promise can be created with its constructor:&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;promise&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="kd"&gt;function&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="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Your application logic goes here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function taken into the constructor is the executor function and takes in two arguments: Resolved and Rejected.&lt;/p&gt;

&lt;p&gt;The code inside this function is the logic to be executed each time a new Promise is created.&lt;/p&gt;

&lt;p&gt;The Promise returned from the constructor should be able to inform the executor function, handling async (asynchronous) operations, when execution has started, completed or returned an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parts of a promise
&lt;/h2&gt;

&lt;p&gt;A promise has a STATE and a RESULT&lt;/p&gt;

&lt;p&gt;A promise has 3 states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pending&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fulfilled&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rejected&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pending&lt;/strong&gt; promises in JavaScript, much like in the real world, is a promise that has been executed but not yet completed and can therefore move to the ‘Fulfilled’ or ‘Rejected’ state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fulfilled&lt;/strong&gt; promises are resolved or completed, indicating a successful outcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rejected&lt;/strong&gt; promises indicate an unsuccessful outcome due to an error or a timeout.&lt;/p&gt;

&lt;p&gt;And, promises that are either Fulfilled or Rejected are called &lt;em&gt;Settled&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The result property of a promise can hold the values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;undefined : When the state is pending&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;value : When resolve(value) is called&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;error : When reject(error) is called&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resolving and Rejecting
&lt;/h2&gt;

&lt;p&gt;The promise can be resolved with &lt;code&gt;resolve()&lt;/code&gt; and placed in the fulfilled state, or rejected with an error as &lt;code&gt;reject(new Error('Something went wrong'))&lt;/code&gt; in and placed in rejected state.&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;myPromise&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="kd"&gt;function&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This will be resolved&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// EXECUTED&lt;/span&gt;
   &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&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="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// ignored&lt;/span&gt;
   &lt;span class="nx"&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;Resolved again?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ignored&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, reject() and resolve() are being called again after the promise has been fulfilled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;But, once the state has changed, any further calls to reject and resolve will be ignored.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling a promise
&lt;/h2&gt;

&lt;p&gt;The handler functions &lt;code&gt;.then()&lt;/code&gt;, &lt;code&gt;.catch()&lt;/code&gt;, &lt;code&gt;.finally()&lt;/code&gt; allow functions consuming the promise to be in sync with the executor function when a promise is fulfilled/rejected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;.then()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is called to handle a promise’s rejection or fulfillment, and can therefore accept up to two functions as arguments:&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;myPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// a successful outcome, promise fulfilled&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;result&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// promise rejected&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;error&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;Or if only one of the two outcomes are needed:&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;// logs SUCCESFUL outcomes only&lt;/span&gt;
&lt;span class="nx"&gt;myPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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;// logs ERROR outcomes only&lt;/span&gt;
&lt;span class="nx"&gt;myPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;h3&gt;
  
  
  Using &lt;code&gt;.catch()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Leaving one argument null in &lt;code&gt;.then()&lt;/code&gt; to handle errors is not so useful. This is when &lt;code&gt;.catch()&lt;/code&gt; used.&lt;/p&gt;

&lt;p&gt;In the following example &lt;code&gt;getPromise()&lt;/code&gt; is a user implemented function that accepts a URL and returns a promise stating its outcome.&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;urlPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BAD_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;consumerFunc&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="nx"&gt;promise&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;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;consumerFunc&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using &lt;code&gt;.finally()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This handler cleans up after an execution (for example, close a live connection) and will run regardless of whether a promise is rejected or fulfilled.&lt;/p&gt;

&lt;p&gt;Here is &lt;code&gt;.finally()&lt;/code&gt; being used with the other handlers:&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;isLoading&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="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;//Promise with outcome of URL&lt;/span&gt;
&lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&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;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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="s2"&gt;`Promise settled and loading is &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="s2"&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;result&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;error&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.finally()&lt;/code&gt; will set &lt;code&gt;isLoading&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the URL is valid, &lt;code&gt;.then()&lt;/code&gt; is executed and &lt;code&gt;result&lt;/code&gt; is logged.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the URL is invalid, &lt;code&gt;error&lt;/code&gt; is caught and &lt;code&gt;.catch()&lt;/code&gt; is executed and &lt;code&gt;error&lt;/code&gt; is logged.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.finally()&lt;/code&gt; will be called regardless of a resolved or rejected promise.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Chaining Promises
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;aPromise.then()&lt;/code&gt; always returns a promise this lets us call &lt;code&gt;.then()&lt;/code&gt; on the new promise leading to a chain of &lt;code&gt;.then()&lt;/code&gt; methods passing down a single promise.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;.then()&lt;/code&gt; can return a new promise, or throw an error too. The following example demonstrates 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;let&lt;/span&gt; &lt;span class="nx"&gt;myPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;URL_RETURNING_MULTIPLE_ITEMS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// extracts URL of oneItem&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;oneItem&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;results&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="nx"&gt;url&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;oneItem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// returns the URL&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneItemURL&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneItemURL&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;getPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneItemURL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// new promise returned&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemData&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="nx"&gt;log&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemData&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;error&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="nx"&gt;caught&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;In&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;Catch&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;Where the new promise is created, the URL from the previous &lt;code&gt;.then()&lt;/code&gt; is passed into &lt;code&gt;getPromise()&lt;/code&gt; which returns the new promise that is then resolved sent down the chain where &lt;code&gt;itemData&lt;/code&gt; is logged.&lt;/p&gt;

&lt;p&gt;If an error is caught, the &lt;code&gt;.catch()&lt;/code&gt; in the chain is triggered and the error is handled.&lt;/p&gt;

&lt;p&gt;And those were the basics of how Promises can be used for asynchronous functions, resulting in clean, understandable code that’s less prone to errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Till next time, happy coding!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>promises</category>
      <category>javascript</category>
      <category>asynchronousprogramming</category>
    </item>
  </channel>
</rss>
