<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ axios - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ axios - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 26 May 2026 04:44:01 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/axios/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Fetch API vs. Axios vs. Alova: Which HTTP Client Should You Use in 2025? ]]>
                </title>
                <description>
                    <![CDATA[ Before the days of the Fetch API and Axios, developers used callback-based HTTP requests. They manually managed requests with asynchronous operations and, in the process, wrote deeply nested code. This was known as callback hell. Then, in 2015, a pro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/fetch-api-vs-axios-vs-alova/</link>
                <guid isPermaLink="false">67ed4e54f03ad9ca955f36d0</guid>
                
                    <category>
                        <![CDATA[ Alova ]]>
                    </category>
                
                    <category>
                        <![CDATA[ XHP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ javascript framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ json ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ blob ]]>
                    </category>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fetch API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fetching apis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API basics  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abdullah Salaudeen ]]>
                </dc:creator>
                <pubDate>Wed, 02 Apr 2025 14:48:52 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743605319873/9f7583a0-1b01-4714-9fe6-f39bed3954e8.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Before the days of the Fetch API and Axios, developers used callback-based HTTP requests. They manually managed requests with asynchronous operations and, in the process, wrote deeply nested code. This was known as callback hell.</p>
<p>Then, in 2015, a promise-based API request, the Fetch API, was built into JavaScript ES6 to ease the process. After that, libraries like Axios and Alova also appeared.</p>
<p>But why would anyone consider using a third-party API when the lightweight inbuilt Fetch API is an effective option? Well, Axios and Alova provide more than just fetching simple JSON responses. While Axios automates the parsing of JSON and provides shorthand methods for requests, Alova caches responses which prevents making new requests that are redundant.</p>
<p>So which should you stick to – Fetch API, Axios, or Alova? </p>
<p>In this guide, we’ll examine each of these tools based on their features, performance, and project suitability. Walk with me…</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-fetch-api">The Fetch API</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-features-of-the-fetch-api">Key Features of the Fetch API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-the-fetch-api">Limitations of the Fetch API</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-axios">Axios</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-features-of-axios">Key Features of Axios</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-axios">Limitations of Axios</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-alova">Alova</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-features-of-alova">Key Features of Alova</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-alova">Limitations of Alova</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-feature-by-feature-comparison">Feature-by-Feature Comparison</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-and-best-scenarios">Use Cases and Best Scenarios</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-when-to-use-fetch-api">When to Use Fetch API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-axios">When to Use Axios</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-alova">When to Use Alova</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-community-and-ecosystem">Community and Ecosystem</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-ecosystem-and-integrations">Ecosystem and Integrations</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start this tutorial, you should have a basic understanding of JavaScript and ES6+ features, such as <a target="_blank" href="https://www.freecodecamp.org/news/javascript-async-await/"><code>async/await</code></a>, <a target="_blank" href="https://www.freecodecamp.org/news/javascript-arrow-functions-in-depth/">arrow functions</a>, and <a target="_blank" href="https://salaudeenabdu.hashnode.dev/destructuring-in-javascript">object destructuring</a>. Being familiar with the <code>fetch()</code> API will also be helpful, as we’ll compare it with Axios and Alova.</p>
<p>You should also have a fundamental knowledge of HTTP methods (GET, POST, PUT, DELETE, PATCH) and handling API responses based on status codes to better understand the API examples.</p>
<p>While this tutorial focuses on JavaScript, some examples use React. So you should be familiar with React and understand the basics of components, state, and hooks (like <code>useState</code> and <code>useEffect</code>). Alova also works with frameworks like Vue and Svelte.</p>
<p>Basic experience with package managers (NPM or Yarn) is useful for installing dependencies like Axios and Alova. And understanding Node.js and browser environments will help, as Alova works in both contexts.</p>
<p>Lastly, familiarity with state management and caching concepts will enhance your understanding of Alova’s features, as it integrates state management and caching directly into API requests.</p>
<h2 id="heading-the-fetch-api"><strong>The Fetch API</strong></h2>
<p>Fetch API is a promise-based API request feature in JavaScript that was released to replace the old callback-based XMLHttpRequest (XHP). Unlike the old tool, Fetch API is compatible with modern website features, including <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">service workers</a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">Cross-Origin Resource Sharing (CORS)</a>. </p>
<p>With this tool, calling API data is as simple as making a fetch() request on the API URL, as shown below:  </p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">"https://fakestoreapi.com/products"</span>)
</code></pre>
<p>The <code>fetch()</code> returns the server’s promise which is fulfilled with a response object. Then, you pass in some optional arguments to configure the response as JSON or text, attach it to a variable, and use the data.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> products;

  fetch(<span class="hljs-string">"https://fakestoreapi.com/products"</span>)

    .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())

    .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {

      products = data

      <span class="hljs-built_in">console</span>.log(products)

    })

    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching data:"</span>, error))
</code></pre>
<p>In the code above, the <code>fetch()</code> requests API data from the URL. The response <code>res</code> gets parsed as JSON <code>res.json</code>. Then, the resulting data is attached to the <code>products</code> variable and logged on the console.  </p>
<p>Since Node.js v17.5, the Fetch API has been available natively, eliminating the reliance on external packages like <code>node-fetch</code>, <code>got</code>, or <code>cross-fetch</code> for handling HTTP requests. This native support in both browsers and Node.js removes the need for additional dependencies, reducing the overall bundle size of your application. With this built-in functionality, the Fetch API has become the go-to tool for making asynchronous API calls in JavaScript applications.</p>
<h3 id="heading-key-features-of-the-fetch-api">Key Features of the Fetch API</h3>
<h4 id="heading-promises-based-syntax">Promises-based syntax</h4>
<p>As I mentioned earlier, the Fetch API uses a promise-based syntax that sends a promise from the server and executes it with a response object. While the <code>.then</code> chaining can be optimal for simple requests, using several <code>.then</code>s can lead to callback hell and give you a hard time tracking errors. This is why the <code>async/await</code> alternative is a more optimal solution. Check out the code example below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

      <span class="hljs-keyword">try</span> {

        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://fakestoreapi.com/products"</span>);

        <span class="hljs-keyword">if</span> (!response.ok) {

          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! Status: <span class="hljs-subst">${response.status}</span>`</span>);

        }

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

        products = data

        <span class="hljs-built_in">console</span>.log(products); <span class="hljs-comment">//</span>

      } <span class="hljs-keyword">catch</span> (error) {

        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching data:"</span>, error);

      }

    };

    fetchData();
</code></pre>
<p>As shown above, the fetch makes a get request. Then, the server returns an error status if the response is not ok (returns an error status like <code>error 404</code>). Then, the response gets parsed as JSON and used. </p>
<p>Keep in mind that all methods passed on the response are asynchronous, including the <code>fetch()</code> and the <code>json()</code> parsing.</p>
<h4 id="heading-supports-the-get-post-put-patch-and-delete-methods">Supports the <code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> methods</h4>
<p><code>GET</code>, used to receive responses, is the Fetch API’s default method. So when you’re using it, you don’t have to define it explicitly or attach a body. But for methods that send requests like <code>POST</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code>, you must specify their method and attach a body. </p>
<p>All these methods send requests to the backend. You can send data to the server with <code>POST</code>,  completely replace an existing resource with new data using <code>PUT</code>, partially update with <code>PATCH</code>, or remove the resource with <code>DELETE</code>.  </p>
<ol>
<li><strong>Here’s how you can define a method:</strong></li>
</ol>
<p>In the code below, I set the POST method to send data to the specified API: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>

          <span class="hljs-comment">//...</span>

        });
</code></pre>
<p>Apart from posting data, you can also clear data on the server using <code>DELETE</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

      <span class="hljs-attr">method</span>: <span class="hljs-string">"DELETE"</span>

      <span class="hljs-comment">//...</span>

    });
</code></pre>
<ol start="2">
<li><strong>Then, define the header:</strong></li>
</ol>
<p>Defining the header lets the server understand the type of content you are sending for proper data handling. As shown here, the header asks the server to store the content as a JSON file and set the authorization token to <code>my-classified-token</code><em>.</em> Keep in mind that the token is the API key that will be used to verify user identity upon use.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,

          <span class="hljs-attr">header</span>: {

            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application-json"</span>,

            <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer my-classified-token"</span>,

          }

          <span class="hljs-comment">//..</span>

        });
</code></pre>
<p>Here is a full list of parameters that can be passed into the header:</p>
<table><tbody><tr><td><p><strong>Header</strong></p></td><td><p><strong>Purpose</strong></p></td></tr><tr><td><p>"Content-Type": "application/json"</p></td><td><p>Tells the server that the request body is in JSON format.</p></td></tr><tr><td><p>"Authorization": "Bearer token"</p></td><td><p>Provides authentication (API keys, JWT, OAuth tokens).</p></td></tr><tr><td><p>"Accept": "application/json"</p></td><td><p>Specifies that the client expects a JSON response.</p></td></tr><tr><td><p>"Content-Type": "application/x-www-form-urlencoded"</p></td><td><p>Used for sending form data instead of JSON.</p></td></tr><tr><td><p>"Origin": "http://example.com"</p></td><td><p>Indicates where the request is coming from (used in CORS).</p></td></tr></tbody></table>

<ol start="3">
<li><strong>Next, attach the body:</strong></li>
</ol>
<p>After specifying the header, you then attach the body. The body is the data being sent to the backend server. It cannot be used with the GET method which only fetches responses. Besides, the information attached should always be in a valid format that matches the content type specified in the headers. You can add as much value as you require to the body.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/products1"</span>, {

          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,

          <span class="hljs-attr">header</span>: {

            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application-json"</span>,

            <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer my-classified-token"</span>,

          },

          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>, <span class="hljs-attr">price</span>: <span class="hljs-number">1200</span> })

        });
</code></pre>
<h4 id="heading-streaming-data">Streaming Data</h4>
<p>It is also worth noting that the Fetch API facilitates large data handling via streaming. It receives copious data in chunks instead of loading the whole data and buffering in the process. So it data displays real-time as they arrive. Here is a simple example of streaming:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://www.example.com/large-text-file.txt'</span>);

      <span class="hljs-keyword">const</span> reader = response.body.getReader();

      <span class="hljs-keyword">const</span> decoder = <span class="hljs-keyword">new</span> TextDecoder();

      <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {

        <span class="hljs-keyword">const</span> { done, value } = <span class="hljs-keyword">await</span> reader.read();

        <span class="hljs-keyword">if</span> (done) <span class="hljs-keyword">break</span>;

        <span class="hljs-keyword">const</span> chunk = decoder.decode(value, { <span class="hljs-attr">stream</span>: <span class="hljs-literal">true</span> });

        <span class="hljs-built_in">console</span>.log(chunk); <span class="hljs-comment">// Process the chunk (e.g., display it in UI)</span>

      }

      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Stream complete'</span>);

    }

    fetchData();
</code></pre>
<h4 id="heading-fetching-documents-with-the-dom-parser">Fetching Documents with the DOM Parser</h4>
<p>Unlike its predecessor, XHP, which can directly return a document, Fetch API can’t achieve the same results without using the DOM Parser. To use it, you have to set the response type to text, then convert to a document using the DOMParser. Here is an example:</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">"example.xml"</span>)

  .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.text()) <span class="hljs-comment">// Get raw text</span>

  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {

    <span class="hljs-keyword">const</span> parser = <span class="hljs-keyword">new</span> DOMParser();

    <span class="hljs-keyword">const</span> doc = parser.parseFromString(data, <span class="hljs-string">"text/xml"</span>); <span class="hljs-comment">// Convert text to Document</span>

    <span class="hljs-built_in">console</span>.log(doc); <span class="hljs-comment">// Now it's a Document object</span>

  })

  .catch(<span class="hljs-built_in">console</span>.error);
</code></pre>
<h4 id="heading-request-cancellation-with-abortcontroller">Request Cancellation with AbortController</h4>
<p>Previously, the Fetch API couldn’t abort requests. But it is now possible with <code>AbortController</code> and <code>AbortSignal</code>. But the AbortController API is not native either, which means there is extra bundle and set up required. </p>
<h3 id="heading-limitations-of-the-fetch-api"><strong>Limitations of the Fetch API</strong></h3>
<h4 id="heading-response-flexibility-or-no-automatic-json-parsing">Response Flexibility or No automatic JSON parsing</h4>
<p>Depends on how you see it. Having to specify whether you want your response as JSON <code>res.json()</code> or text <code>res.text()</code> or blob <code>res.blob()</code> lets you set which response type you want from the get go. But it can also be a limitation since most API fetches are in JSON. This means that alternatives like Axios, which sets defaults as <code>res.json()</code>, helps write shorter and cleaner code, and is therefore often preferred by developers. </p>
<h4 id="heading-no-built-in-requestresponse-interceptors">No built-in request/response interceptors</h4>
<p>Unlike Axios, Fetch API does not have built-in methods that intercept and modify requests or responses. This limitation means you have to write boilerplate code to create a custom interceptor.</p>
<p>For instance, via interception, you can attach an Authorization token automatically before sending requests or asking all 401 errors to automatically reload when receiving responses. With the Fetch API, you have to wrap the <code>fetch()</code> in a function to do that, which means more lines of code.</p>
<p>Here is some code built to mimic request/ response interception:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> customFetch = <span class="hljs-keyword">async</span> (url, options = {}) =&gt; {

      <span class="hljs-comment">// Request Interception</span>

      <span class="hljs-keyword">const</span> modifiedOptions = {

          ...options,

          <span class="hljs-attr">headers</span>: {

              <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,

              <span class="hljs-attr">Authorization</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)}, <span class="hljs-comment">// Interceptor behavior</span>

              ...options.headers

          }

      };



      <span class="hljs-keyword">try</span> {

          <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url, modifiedOptions);



          <span class="hljs-comment">// Response Interception</span>

          <span class="hljs-keyword">if</span> (!response.ok) {

              <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Intercepted Error:"</span>, response.status);

          }



          <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.json();

      } <span class="hljs-keyword">catch</span> (error) {

          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Fetch error intercepted:"</span>, error);

          <span class="hljs-keyword">throw</span> error;

      }

  };

  <span class="hljs-comment">// Usage (No need to set headers manually)</span>

  customFetch(<span class="hljs-string">'https://api.example.com/data'</span>)

      .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(data))

      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<h4 id="heading-error-handling-requires-additional-logic">Error handling requires additional logic</h4>
<p>The Fetch API only rejects network errors, not failed HTTP status codes like 404 or 501. This means that when a fetching request fails, it does not return a  <code>404 Not Found</code> or <code>500 Internal Server Error</code> unless you configure that with additional code. But Axios does.  </p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/invalid-url'</span>)

  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {

    <span class="hljs-keyword">if</span> (!response.ok) { <span class="hljs-comment">// Manually handle non-2xx responses</span>

      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP Error! Status: <span class="hljs-subst">${response.status}</span>`</span>);

    }

    <span class="hljs-keyword">return</span> response.json();

  })

  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(data))

  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error:'</span>, error.message));
</code></pre>
<h2 id="heading-axios"><strong>Axios</strong></h2>
<p>After XHP was replaced with the Fetch API, <a target="_blank" href="https://axios-http.com/docs/intro">Axios</a> emerged in 2016 to address some issues with the new JavaScript-native fetching tool. Built on top of XHP, Axios quickly gained widespread adoption due to combining many Fetch API promise-based features with some methods on the legacy XMLHttpRequest. In no time, it became a popular choice amongst developers.</p>
<p>Axios stands out because it:</p>
<ul>
<li><p>Automates JSON parsing</p>
</li>
<li><p>Has a built-in method to intercept and modify requests and responses </p>
</li>
<li><p>Automates error handling </p>
</li>
<li><p>Automates timeout handling</p>
</li>
<li><p>Can track upload and download progress</p>
</li>
</ul>
<p>And many more features.</p>
<p>In particular, Axios is widely loved because it reduces boilerplate code. Since most API requests encode data with <code>JSON</code>, Axios sets its default parsing to accordingly, which means you don’t have to define <code>JSON</code> again. And why worry anyway, since developers use far fewer <code>res.text()</code> and <code>res.blob()</code> API responses in comparison.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>);

    <span class="hljs-built_in">console</span>.log(response.data); <span class="hljs-comment">// JSON is already parsed</span>

  };
</code></pre>
<p>Now, compare that to a like-for-like fetching with Fetch API:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);

    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json(); <span class="hljs-comment">// Extra step</span>

    <span class="hljs-built_in">console</span>.log(data);

  };
</code></pre>
<p>Yeah, there’s an extra line, right? That could mean several lines of code for larger codebases. </p>
<h3 id="heading-key-features-of-axios"><strong>Key Features of Axios</strong></h3>
<h4 id="heading-automatic-json-parsing">Automatic JSON Parsing</h4>
<p>As explained above, you don’t have to call <code>res.json()</code> again while using Axios, since the method is automatically set. But what happens, in rare cases, when you want to fetch a blob or text using Axios? Then, you have to set the response type accordingly. Here’s how you can do that:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>, {
      <span class="hljs-attr">responseType</span>: <span class="hljs-string">'text'</span>, <span class="hljs-comment">// Treats response as plain text</span>
    });

    <span class="hljs-built_in">console</span>.log(response.data); <span class="hljs-comment">// Plain text string</span>
  };
</code></pre>
<h4 id="heading-built-in-interceptors-to-modify-requests-and-responses">Built-in Interceptors to Modify Requests and Responses</h4>
<p>Axios comes with its built-in interceptors to intercept and modify API responses or requests. Interceptors can help set authorization tokens for requests or modify global responses and errors before they render. Use the <code>.interceptors.request.use()</code> for requests and <code>.interceptors.response.use()</code> for responses. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

  <span class="hljs-keyword">const</span> apiClient = axios.create({

      <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://api.example.com"</span>,

      <span class="hljs-attr">headers</span>: {

          <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>

      }

  });



  <span class="hljs-comment">// Request Interceptor: Attach Authorization headers</span>

  apiClient.interceptors.request.use(<span class="hljs-function"><span class="hljs-params">config</span> =&gt;</span> {

      config.headers.Authorization = Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)};

      <span class="hljs-keyword">return</span> config;

  }, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">Promise</span>.reject(error));

  <span class="hljs-comment">// Usage: Axios automatically includes the Authorization header</span>

  apiClient.get(<span class="hljs-string">"/data"</span>)

      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<p>To achieve that with Fetch API, you will have to write an interceptor wrapper on your API, which needs far more boilerplate code.</p>
<h4 id="heading-request-cancellation-with-canceltoken">Request cancellation with CancelToken</h4>
<p>Although now deprecated, Axios used to have its native request cancellation method known as <code>CancelToken</code>. But now, the <code>AbortController</code> API is regarded as a globally-recognized and reliable method for request abortion.</p>
<h4 id="heading-error-handling">Error Handling</h4>
<p>Axios handles errors better by automatically rejecting all non-2xx status codes like <code>Error 404</code> and <code>501</code>. You do not need to check any <code>response.ok</code> message:</p>
<pre><code class="lang-javascript">axios.get(<span class="hljs-string">'https://jsonplaceholder.typicode.com/invalid-url'</span>)

  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error Status:'</span>, error.response?.status); <span class="hljs-comment">// Axios auto-rejects non-2xx responses</span>

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error Message:'</span>, error.message);

  });
</code></pre>
<h4 id="heading-built-in-progress-tracking">Built-in Progress Tracking</h4>
<p>Axios incorporates XHP methods like <code>onDownloadProgress</code> and <code>onUploadProgress</code>. This inbuilt feature facilitates tracking download and uploads progress. Whereas with the Fetch API, you’d need <code>ReadableStream</code> to achieve similar results. </p>
<p>Here is an example showing how you can use <code>onUploadProgress</code>: </p>
<pre><code class="lang-javascript">axios.post(url, data, {

    <span class="hljs-attr">onUploadProgress</span>: <span class="hljs-function"><span class="hljs-params">progressEvent</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(progressEvent.loaded)

  });
</code></pre>
<h4 id="heading-supports-other-methods-too">Supports Other Methods, too</h4>
<p>Just like the Fetch API, Axios’ default Method is <code>GET</code>. But you can use the <code>POST</code>, <code>PUT</code>, <code>PATCH</code> or <code>DELETE</code> methods using <code>axios.request()</code>. Here’s how:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

  axios.request({

      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,

      <span class="hljs-attr">url</span>: <span class="hljs-string">"https://api.example.com/users"</span>,

      <span class="hljs-attr">body</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">"Abdullah"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }, <span class="hljs-comment">// Request body</span>

      <span class="hljs-attr">headers</span>: {

          <span class="hljs-string">"Authorization"</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)},

          <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>

      }

  })

  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios Request Error:"</span>, error));
</code></pre>
<p>Axios also provides a shorthand with methods like <code>axios.get</code>, <code>axios.post</code>, <code>axios.put</code>, <code>axios.patch</code>, and <code>axios.delete</code>, as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// POST Request</span>

axios.post(<span class="hljs-string">"https://api.example.com/users"</span>,

  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Abdullah"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span> }, <span class="hljs-comment">// Request body</span>

  { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> } }

)

.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios POST Error:"</span>, error));

<span class="hljs-comment">// PUT Request</span>

axios.put(<span class="hljs-string">"https://api.example.com/users/123"</span>,

  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Updated Name"</span> }, <span class="hljs-comment">// Updated data</span>

  { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Authorization"</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)} } }

)

.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))

.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios PUT Error:"</span>, error));

<span class="hljs-comment">// DELETE Request</span>

axios.delete(<span class="hljs-string">"https://api.example.com/users/123"</span>, {

  <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Authorization"</span>: Bearer ${<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>)} }

})

.then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"User deleted successfully"</span>))

.catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Axios DELETE Error:"</span>, error));
</code></pre>
<h3 id="heading-limitations-of-axios"><strong>Limitations of Axios</strong></h3>
<h4 id="heading-slightly-larger-bundle-size">Slightly larger bundle size</h4>
<p>Axios <a target="_blank" href="https://bundlephobia.com/package/axios@1.8.4">adds 35 kb</a> of extra bundle, while FetchAPI adds 0. While Axios clearly offers more features than Fetch in every other metric, you have to make do with the larger bundle size. And in an age where lightweight and fast applications are often preferred, you might not want that load.</p>
<h4 id="heading-dependency-on-third-party-maintenance">Dependency on third-party maintenance</h4>
<p>Depending on a third-party option for something as crucial as API might not be desirable. So a native tool like the Fetch API, built within JavaScript, offers more reliability.</p>
<h2 id="heading-alova"><strong>Alova</strong></h2>
<p><a target="_blank" href="https://github.com/alovajs/alova">Alova</a> is a request management library that combines simple API fetching with other functionalities like state management, hooks, and caching, amongst many others.</p>
<p>While we use <code>react-query</code> and <code>SWR</code> to process Axios-fetched data, Alova saves you those extra installations and coding by providing these methods natively. The all-in-one alternative not only fetches responses and sends requests, but also merges requests, caches responses, and optimizes them for UI frameworks. </p>
<p>Built in 2022, Alova’s adoption is still early but nonetheless seems promising. It is supported on browsers, Node.js, and most frameworks, including Vue, React, Svelte, and vanilla JavaScript. But it has limited usage for Angular.js.</p>
<p><a target="_blank" href="https://bundlephobia.com/package/alova@2.6.1">At just 10kb</a>, it is about 3 times smaller than Axios, making it a more lightweight alternative for building fast applications. </p>
<p>You can also use Alova to either replace react-query to facilitate Axios or be the one-stop-shop for everything API integration-related. </p>
<p>Here is a simple Alova fetch:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> alovaInstance.Get(<span class="hljs-string">'https://jsonplaceholder.typicode.com'</span>).send();

<span class="hljs-built_in">console</span>.log(response); <span class="hljs-comment">// Response data</span>
</code></pre>
<p>When you are fetching Alova on React components, you can use the <code>createAlova()</code> to set parameters and <code>useRequest()</code> to manage state. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { createAlova, useRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"alova"</span>;

<span class="hljs-keyword">import</span> GlobalFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"alova/GlobalFetch"</span>;

<span class="hljs-comment">// Initialize Alova</span>

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-comment">// GET request with useRequest</span>

<span class="hljs-keyword">const</span> Profile = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { data, loading, error } = useRequest(<span class="hljs-function">() =&gt;</span> alovaInstance.Get(<span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>));

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error fetching profile<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Username: {data.username}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;

};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Profile;
</code></pre>
<h3 id="heading-key-features-of-alova"><strong>Key Features of Alova</strong></h3>
<h4 id="heading-one-stop-shop">One-Stop Shop</h4>
<p>For some functionalities that come built into Alova, Fetch API or Axios might need additional libraries like <code>react-query</code> or <code>SWR</code> to fulfill. </p>
<h4 id="heading-request-sharing-prevents-redundant-requests">Request Sharing Prevents Redundant Requests</h4>
<p>Alova fuses identical requests. Let’s say several components ask for the same data from the API. The Fetch API and Axios send multiple identical requests to the server which creates traffic. But Alova merges them, sends a single request, and shares its response across all components, which reduces network traffic.</p>
<h4 id="heading-state-management">State Management</h4>
<p>With tools like Fetch API and Axios, you have to manage data, loading, and error states manually. Alova lets you do that on the go within a single line of code. Here is how it looks:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>

<span class="hljs-keyword">const</span> { data, loading, error } = useRequest(alova.Get(<span class="hljs-string">"/posts/1"</span>));

<span class="hljs-comment">//...</span>
</code></pre>
<h4 id="heading-advanced-request-management">Advanced Request Management</h4>
<p>Alova offers several request management functionalities with each tailored to specific use cases. With its request management, you can request preload for data to be used later, cache data to prevent reload, manage form submission, handle pagination, and automate refetching when needed. Check out their docs to <a target="_blank" href="https://alova.js.org/tutorial/client/strategy/">read more</a>. </p>
<h4 id="heading-multi-level-caching">Multi-Level Caching</h4>
<p>You can also use Alova to cache data, especially when the response isn’t constantly changing and does not need refetching. Unlike <code>react-query</code> that simply stores caches in RAM, Alova offers a more flexible framework. </p>
<p>Its three-pronged caching modes include the memory mode, cache occupying mode, and recovery mode. While memory mode stores data in the RAM, recovery mode persistently stores it in a Local Storage and is made available for longer periods and even offline. Meanwhile, the occupying mode prevents duplicate or redundant requests coming in quick succession. </p>
<p>Independent on any component, cached data can be accessed anywhere in the app if the request URL and parameters match. These features lower traffic going to servers, reduce buffering, and help facilitating a swifter and better user experience.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>

<span class="hljs-comment">// Initialize Alova instance</span>

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>,

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-comment">// Define GET request</span>

<span class="hljs-keyword">const</span> getPosts = alovaInstance.Get(<span class="hljs-string">"/posts"</span>, {

  <span class="hljs-attr">cache</span>: {

    <span class="hljs-attr">mode</span>: <span class="hljs-string">"memory"</span>, <span class="hljs-comment">// Caches in memory</span>

    <span class="hljs-attr">expires</span>: <span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">5</span>, <span class="hljs-comment">// Expires in 5 minutes</span>

  },

});

<span class="hljs-keyword">const</span> PostList = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { data, loading, error } = useRequest(getPosts);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Error fetching data<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;

  <span class="hljs-comment">//...</span>

};
</code></pre>
<p>In the example above, Alova caches the response using the memory mode <code>cache: {mode: "memory"}</code> and sets the cache expiration to 5 minutes <code>expires: 1000 * 60 * 5</code><em>.</em> You can change <code>“memory”</code> to <code>“recovery”</code> if you want a longer storage duration. </p>
<h4 id="heading-usage-flexibility">Usage Flexibility</h4>
<p>You can use Alova with either Axios or the Fetch API. Here is an example where I fetched data using Axios and complemented it with Alova state management.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>

<span class="hljs-comment">// Initialize Alova</span>

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-comment">// Manage state with Alova</span>

<span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: posts, setData } = useSnapshot([]);

<span class="hljs-keyword">const</span> fetchPosts = <span class="hljs-keyword">async</span> () =&gt; {

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>);

  setData(response.data); <span class="hljs-comment">// Store data in Alova state</span>

};

<span class="hljs-comment">//...</span>
</code></pre>
<h4 id="heading-supports-other-methods">Supports Other Methods</h4>
<p>Alova also makes <code>GET</code> its default option while supporting other methods like <code>POST</code>, <code>PATCH</code>, <code>PUT</code> and <code>DELETE</code>. Here is how to use <code>POST</code> in Alova, for example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { createAlova, useRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"alova"</span>;

<span class="hljs-keyword">import</span> GlobalFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"alova/GlobalFetch"</span>;

<span class="hljs-keyword">const</span> alovaInstance = createAlova({

  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>,

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-keyword">const</span> PostForm = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: createPost } = useRequest(alovaInstance.Post(<span class="hljs-string">"/posts"</span>, { title }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

  createPost().then(<span class="hljs-built_in">console</span>.log)

};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PostForm;
</code></pre>
<p>Of course, it has shorthand methods too:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { createAlova, useRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">"alova"</span>;

<span class="hljs-keyword">import</span> GlobalFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"alova/GlobalFetch"</span>;

<span class="hljs-keyword">const</span> alova = createAlova({

  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>,

  <span class="hljs-attr">statesHook</span>: React,

  <span class="hljs-attr">requestAdapter</span>: GlobalFetch(),

});

<span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: createPost } = useRequest(alova.Post(<span class="hljs-string">"/posts"</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">"New Post"</span> }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

<span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: updatePost } = useRequest(alova.Put(<span class="hljs-string">"/posts/1"</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">"Updated Post"</span> }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

<span class="hljs-keyword">const</span> { <span class="hljs-attr">send</span>: patchPost } = useRequest(alova.Patch(<span class="hljs-string">"/posts/1"</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">"Patched Post"</span> }), { <span class="hljs-attr">immediate</span>: <span class="hljs-literal">false</span> });

createPost().then(<span class="hljs-built_in">console</span>.log);

updatePost().then(<span class="hljs-built_in">console</span>.log);

patchPost().then(<span class="hljs-built_in">console</span>.log);
</code></pre>
<h4 id="heading-bundle-size">Bundle Size</h4>
<p>Alova is three times smaller than Axios, but that does not even tell the full story. With Axios and the Fetch API, you need different libraries to handle caching, request deduplication, and retries. But Alova has everything in-built. So using Axios and Fetch API in real code production will always require more bundles than Axios. And overall, Alova facilitates lighter-weight applications compared to Axios and sometimes the Fetch API as well. </p>
<h3 id="heading-limitations-of-alova"><strong>Limitations of Alova</strong></h3>
<h4 id="heading-adoption-is-still-low">Adoption Is Still Low</h4>
<p>While writing this article, I had a hard time getting enough resources on Alova. And that is because it only debuted in July 2022 which means adoption is still early. So, troubleshooting Alova might be problematic since there are fewer Alova-themed API communities, as well as fewer StackOverflow answers, Youtube Tutorials, or GitHub contributions. </p>
<h4 id="heading-potential-stability-amp-long-term-maintenance-risks">Potential Stability &amp; Long-Term Maintenance Risks</h4>
<p>Newer libraries have a higher risk of abandonment. Axios has been around for years, while Alova is still growing. Besides, it has fewer production use cases and battle-tested applications compared to Axios and Fetch.</p>
<h4 id="heading-learning-curve">Learning Curve</h4>
<p>Alova’s learning curve can take some getting used to because it handles API requests differently from tools like Axios or the Fetch API.</p>
<p>Instead of making requests directly, you work with request instances and manage state within Alova’s system. This requires learning new ways to structure API calls and use features like caching and request merging. While it may feel unfamiliar at first, it can help reduce redundant API calls and improve performance once you understand it.</p>
<h4 id="heading-fewer-third-party-integrations">Fewer Third Party Integrations</h4>
<p>Alova has fewer third-party libraries built specifically for it, requiring more manual work for compatibility with existing tools. </p>
<h2 id="heading-feature-by-feature-comparison"><strong>Feature-by-Feature Comparison</strong></h2>
<table><tbody><tr><td><p><strong>Feature</strong></p></td><td><p><strong>Fetch API</strong></p></td><td><p><strong>Axios</strong></p></td><td><p><strong>Alova</strong></p></td></tr><tr><td><p><strong>Ease of Use</strong></p></td><td><p>Medium (requires manual handling)</p></td><td><p>High (user-friendly syntax)</p></td><td><p>Medium (requires new patterns)</p></td></tr><tr><td><p><strong>Performance</strong></p></td><td><p>High (lightweight, native)</p></td><td><p>Medium (slightly larger size)</p></td><td><p>High (optimized for caching &amp; batch requests)</p></td></tr><tr><td><p><strong>JSON Handling</strong></p></td><td><p>Manual parsing (.json())</p></td><td><p>Automatic</p></td><td><p>Automatic</p></td></tr><tr><td><p><strong>Request Cancellation</strong></p></td><td><p>AbortController (manual)</p></td><td><p>Built-in with CancelToken</p></td><td><p>Built-in</p></td></tr><tr><td><p><strong>Interceptors</strong></p></td><td><p>No</p></td><td><p>Yes</p></td><td><p>Yes</p></td></tr><tr><td><p><strong>Timeout Handling</strong></p></td><td><p>No (manual with AbortController)</p></td><td><p>Yes (built-in)</p></td><td><p>Yes (built-in)</p></td></tr><tr><td><p><strong>Data Caching</strong></p></td><td><p>No</p></td><td><p>No (requires third-party caching)</p></td><td><p>Yes (built-in)</p></td></tr><tr><td><p><strong>Retry Mechanism</strong></p></td><td><p>No</p></td><td><p>Yes</p></td><td><p>Yes</p></td></tr><tr><td><p><strong>Error Handling</strong></p></td><td><p>Requires manual handling</p></td><td><p>Automatic rejection for non-2xx status codes</p></td><td><p>Built-in error recovery</p></td></tr><tr><td><p><strong>Browser Support</strong></p></td><td><p>All modern browsers</p></td><td><p>All modern browsers</p></td><td><p>All modern browsers</p></td></tr><tr><td><p><strong>Node.js Support</strong></p></td><td><p>Yes</p></td><td><p>Yes</p></td><td><p>Limited</p></td></tr></tbody></table>

<h2 id="heading-use-cases-and-best-scenarios"><strong>Use Cases and Best Scenarios</strong></h2>
<p>Choosing the right HTTP client for your project depends on several factors, including project complexity, dependencies, and performance considerations. Let’s explore when it’s best to use the Fetch API, Axios, or Alova.</p>
<h3 id="heading-when-to-use-fetch-api">When to Use Fetch API</h3>
<ol>
<li><h4 id="heading-suitable-for-lightweight-projects-and-simple-requests">Suitable for Lightweight Projects and Simple Requests</h4>
</li>
</ol>
<p>The Fetch API is built into modern browsers and is ideal for handling basic HTTP requests without adding dependencies. If your project requires only simple GET, POST, or DELETE requests with minimal configurations, Fetch API is a great choice.</p>
<ol start="2">
<li><h4 id="heading-when-working-in-environments-where-third-party-libraries-are-restricted">When Working in Environments Where Third-Party Libraries Are Restricted</h4>
</li>
</ol>
<p>Certain enterprise or security-sensitive applications may restrict the use of external libraries. Since the Fetch API is built into the browser, it remains a viable option when third-party packages like Axios or Alova are not allowed.</p>
<ol start="3">
<li><h4 id="heading-when-minimal-dependencies-are-preferred">When Minimal Dependencies Are Preferred</h4>
</li>
</ol>
<p>Since Fetch API is native to JavaScript, it does not require installing extra libraries, making it perfect for projects that need to keep dependencies low. This can be particularly beneficial for small lightweight apps or static websites.</p>
<h3 id="heading-when-to-use-axios">When to Use Axios</h3>
<ol>
<li><h4 id="heading-ideal-for-backend-heavy-applications-or-complex-apis">Ideal for Backend-Heavy Applications or Complex APIs</h4>
</li>
</ol>
<p>For projects that require multiple API calls, error handling, and efficient request management, Axios is a solid choice. It allows concurrent requests, request cancellation, and improved control over HTTP headers.</p>
<ol start="2">
<li><h4 id="heading-when-automatic-json-handling-interceptors-and-robust-error-handling-are-needed">When Automatic JSON Handling, Interceptors, and Robust Error Handling Are Needed</h4>
</li>
</ol>
<p>Axios simplifies working with JSON data by automatically parsing responses. It also provides built-in interceptors for request and response transformations, as well as superior error handling compared to Fetch API.</p>
<ol start="3">
<li><h4 id="heading-useful-when-working-with-nodejs-in-full-stack-applications">Useful When Working with Node.js in Full-Stack Applications</h4>
</li>
</ol>
<p>Axios works both in the browser and in Node.js, making it an excellent choice for full-stack applications where a unified API client is needed across the frontend and backend.</p>
<h3 id="heading-when-to-use-alova">When to Use Alova</h3>
<ol>
<li><h4 id="heading-when-working-with-frontend-heavy-applications-react-vue-svelte">When Working with Frontend-Heavy Applications (React, Vue, Svelte)</h4>
</li>
</ol>
<p>Alova integrates well with frontend frameworks and state management tools, making it a great choice for single-page applications (SPAs) that depend on smooth data fetching, pagination, and updates.</p>
<ol start="2">
<li><h4 id="heading-best-for-projects-requiring-optimized-caching-and-data-synchronization">Best for Projects Requiring Optimized Caching and Data Synchronization</h4>
</li>
</ol>
<p>Alova is designed for performance optimization and better caching strategies. It is suitable for applications that rely on real-time data synchronization and need to minimize redundant network requests.</p>
<ol start="3">
<li><h4 id="heading-when-performance-optimization-and-reduced-network-load-are-priorities">When Performance Optimization and Reduced Network Load Are Priorities</h4>
</li>
</ol>
<p>With its intelligent caching mechanisms, Alova can significantly reduce API call frequency, thereby improving the overall performance of the application. It is especially useful in scenarios where network efficiency is crucial, such as mobile applications or progressive web apps (PWAs).</p>
<h2 id="heading-community-and-ecosystem"><strong>Community and Ecosystem</strong></h2>
<p>The community and ecosystem surrounding an HTTP client can impact ease of use, available learning resources, and integration with other tools. Let's explore how the Fetch API, Axios, and Alova are perceived in 2025.</p>
<h3 id="heading-ecosystem-and-integrations"><strong>Ecosystem and Integrations</strong></h3>
<p>While Fetch API is widely supported, developers often supplement it with additional libraries for improved caching, timeouts, and request queuing. This can lead to increased development effort compared to using an out-of-the-box solution like Axios or Alova.</p>
<p>Meanwhile, Axios benefits from a well-established ecosystem with a variety of plugins and extensions, making it easy to integrate with different backend architectures, authentication systems, and request monitoring tools.</p>
<p>Alova is designed to work seamlessly with modern state management libraries such as React Query and Vue Query. These integrations make it an attractive choice for developers focused on optimizing frontend data fetching strategies.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Choosing between the Fetch API, Axios, and Alova depends on your project’s needs and priorities. The Fetch API is best for lightweight applications that require minimal dependencies, while Axios is a robust choice for full-stack applications and backend-heavy environments. Alova, on the other hand, is an excellent option for optimizing data fetching and caching in frontend-focused applications.</p>
<p>As developers explore new ways to enhance performance and reduce network load, Alova's adoption is expected to grow, particularly in SPAs and PWAs. But Axios remains a reliable and widely adopted solution, while the Fetch API continues to be the fundamental building block for HTTP requests in JavaScript.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create an Inventory List with React useReducer, Axios, and JSON Server ]]>
                </title>
                <description>
                    <![CDATA[ When it comes to web development, it's hard to ignore React.js. It has been one of the leading user interface libraries for a decade, and it supports a lot of popular frameworks like Next.js in the background. If you are a React developer, you likely... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-an-inventory-list-with-react-usereducer-axios-and-json-server/</link>
                <guid isPermaLink="false">66bdffd3422f318982ba47c0</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tapas Adhikary ]]>
                </dc:creator>
                <pubDate>Thu, 07 Mar 2024 15:33:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/inventory-list.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When it comes to web development, it's hard to ignore React.js. It has been one of the leading user interface libraries for a decade, and it supports a lot of popular frameworks like Next.js in the background.</p>
<p>If you are a React developer, you likely appreciate its component-based architecture, uni-directional data binding, huge community support, and the React team's passion for bringing features in front of developers.</p>
<p>If you are just getting started with React or a beginner at it, that's great – there's a complete <a target="_blank" href="https://www.freecodecamp.org/news/react-fundamentals-for-beginners/">React.js roadmap published here</a> on the freeCodeCamp you can check out. And I think you'll find the library a lot easier to learn if you have a solid grip on basic JavaScript foundations.</p>
<p>Irrespective of where you stand with React, the real fun is in building things with it, don't you agree? So I thought of building a simple <code>inventory list</code> to explain a few powerful concepts like complex state management with useReducer. </p>
<p>And while we're doing that, we'll also create a mock API server using <code>JSON Server</code>, we'll use <code>axios</code> to call the API, and finally we'll use the <code>useReducer</code> hook to manage state.</p>
<p>Sounds interesting? Let's do it. If you would also like to check out the video version of this project, here it is: 😊</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/jKyAEj0EvAA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-project-setup-with-react-and-tailwindcss">Project Setup with React and TailwindCSS</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-a-server-with-json-server">How to Setup a Server with JSON Server</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-and-use-axios">How to Set Up and Use Axios</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-usereducer-hook-from-react">How to Use the useReducer Hook from React</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-actions">How to Create Actions</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-an-inventory-reducer">How to Create an Inventory Reducer</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-inventory-list-component">How to Build the Inventory List Component</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-axios-to-fetch-data-and-dispatch-it-to-the-reducer">How to Use Axios to Fetch Data and Dispatch it to the Reducer</a></li>
<li><a class="post-section-overview" href="#heading-lets-complete-the-jsx-part">Let's Complete the JSX Part</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-inventory-list-in-the-app-component">How to Use the Inventory List in the App Component</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ul>
<h2 id="heading-project-setup-with-react-and-tailwindcss">Project Setup with React and TailwindCSS</h2>
<p>Before we do anything else, let's get the project set up. Also, you can follow along with the <a target="_blank" href="https://github.com/atapas/youtube/tree/main/react/27-inventory-useReducer-jsonserver-axios">source code</a> as you read through.</p>
<p>To build this app, we will use React with <code>Vite</code> and <code>TailwindCSS</code>. You can set up these tools by following a few steps from the <a target="_blank" href="https://vitejs.dev/guide/">Vite</a> and <a target="_blank" href="https://tailwindcss.com/docs/guides/vite">TailwindCSS</a> documentation.</p>
<p>But, why not use something that provides everything built together? This will save you time for future React projects as you can use the same infrastructure to create a React projects every time.</p>
<p>Head over to this <a target="_blank" href="https://github.com/atapas/vite-tailwind-react">repository</a> and click on the <code>Use this template</code> button as indicated in the image below. It will help you create a brand new repository out of a template repository with Vite, React, and TailwindCSS configured.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-12-at-5.25.29-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a React Project Repository with TailwindCSS and Vite from an Existing Template</em></p>
<p>Now provide a suitable name to your repository (let's call it <code>inventory-list</code> in this article) along with a description. You may chose to keep the repository private if you wish to, otherwise go ahead and create the repository by clicking on the button at the bottom.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-12-at-5.30.34-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Provide the Details of the New Repository</em></p>
<p>That's it. You have a repository with all the basic ingredients to get started. Now, go to the command prompt/terminal and clone the newly created repository:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> &lt;YOUR NEWLY CREATED REPOSITORY URL&gt;
</code></pre>
<p>Change directories to the project directory and install the project dependencies using the following commands:</p>
<pre><code class="lang-bash"><span class="hljs-comment">## Change to the project directory</span>
<span class="hljs-built_in">cd</span> inventory-list

<span class="hljs-comment">## Install dependencies</span>

<span class="hljs-comment">## Using NPM</span>
npm install

<span class="hljs-comment">## Using Yarn</span>
yarn install

<span class="hljs-comment">## Using PNPM</span>
pnpm install
</code></pre>
<p>After the dependencies are installed successfully, execute the following command to run the project on a local server:</p>
<pre><code class="lang-bash"><span class="hljs-comment">## Run the project locally</span>

<span class="hljs-comment">## Using NPM</span>
npm run dev

<span class="hljs-comment">## Using Yarn</span>
yarn dev

<span class="hljs-comment">## Using PNPM</span>
pnpm dev
</code></pre>
<p>Now the project should be running locally and should be accessible on the default URL, <code>http://localhost:5173</code>. You can access the URL on yor browser and import the project source code into your favourite code editor (I use VS Code). We are all set to start the coding.</p>
<h2 id="heading-how-to-setup-a-server-with-json-server">How to Setup a Server with JSON Server</h2>
<p><code>JSON Server</code> is the go-to option when you want to work with fake/mock APIs to serve data of your choice. It is easy to set up and customize to your use case. </p>
<p>Let's set up the JSON Server for our project. The first thing is to install it.</p>
<p>Open a terminal at the root of the project folder and type the following command to install JSON Server:</p>
<pre><code class="lang-shell">## Using NPM
npm install json-server

## Using Yarn
yarn add json-server

## Using PNPM
pnpm install json-server
</code></pre>
<p>JSON Server uses JSON files as the data sources to perform HTTP operations like GET/POST/PUT/PATCH/DELETE. Create a <code>server/database</code> directory under the <code>src/</code> directory. Now create a file called <code>data.json</code> under the <code>src/server/database/</code> with the following content:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"edibles"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🍌"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Banana"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">32</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">200</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"fruits"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🍓"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Strawberry"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">52</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"fruits"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🍗"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Checken"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">110</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">190</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"foods"</span>,
      <span class="hljs-attr">"sub-type"</span>: <span class="hljs-string">"Non-Veg"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">4</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🥬"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Lettuce"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">12</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">50</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"Vegetables"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">5</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🍅"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Tomato"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">31</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">157</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"Vegetables"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">6</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🥩"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Mutton"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">325</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">90</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"Non-Veg"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">7</span>,
      <span class="hljs-attr">"picture"</span>: <span class="hljs-string">"🥕"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Carrot"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">42</span>,
      <span class="hljs-attr">"quantity"</span>: <span class="hljs-number">190</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"Vegetables"</span>
    }
  ]
}
</code></pre>
<p>The <code>data.json</code> file contains an array of edible items. Each of the items in the array has properties like picture, name, price, quantity, and type to show in the inventory list.</p>
<p>The last thing left is to add a script into the <code>package.json</code> file so that we can start the JSON Server easily every time. Open the package.json file and add this line inside the <code>scripts</code> object like this:</p>
<pre><code class="lang-json"><span class="hljs-string">"start-server"</span>: <span class="hljs-string">"json-server --watch ./src/server/database/data.json"</span>
</code></pre>
<p>Next, go to the terminal and use the following command to start the JSON Server to serve the API:</p>
<pre><code class="lang-shell">## Using NPM
npm run start-server

## Using Yarn
yarn start-server

## Using PNPM
pnpm run start-server
</code></pre>
<p>You should see a message like this in your terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-07-at-8.46.32-AM-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Output</em></p>
<p>It indicates that the JSON Server is running locally on <code>localhost:3000</code> and there is an API endpoint called <code>edibles</code> serves the data. Now you can access the URL <code>http://localhost:3000/edibles</code> from your browser to see the data (fetched by a GET method call):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>The API Output</em></p>
<p>Great! Now we have the <code>/edibles</code> API endpoint ready to consume into the React component.</p>
<h2 id="heading-how-to-set-up-and-use-axios">How to Set Up and Use Axios</h2>
<p><code>Axios</code> is an HTTP client that helps us make promise-based asynchronous calls from the browser and Node.js environment. It has a number of <a target="_blank" href="https://www.npmjs.com/package/axios#features">useful features</a> that make it one of the most used libraries for asynchronous request-response.</p>
<p>Note that we could have used the <code>fetch Web API</code> from JavaScript instead of <code>Axios</code> in this project. The only reason for using Axios here is to introduce it progressively. In the future articles, you'll learn its usages in handling JWT tokens from a React application. Stay tuned!</p>
<p>Open the terminal at the root of the project folder and use the following command to install Axios:</p>
<pre><code class="lang-shell">## Using NPM
npm install axios

## Using Yarn
yarn add axios

## Using PNPM
pnpm install axios
</code></pre>
<p>That's it. We will use Axios in a bit after laying out the basic components needed for the inventory list.</p>
<h2 id="heading-how-to-use-the-usereducer-hook-from-react">How to Use the useReducer Hook from React</h2>
<p>React is a user interface library that supports component-based architecture at the core. A component is a single entity that's supposed to perform one task well. Multiple components come together to compose the final user interface.</p>
<p>Often, a component will have its own private data. We call these the <code>states</code> of a component. The value of a state drives the behaviour and appearance of a component. When state changes, the component re-renders to keep itself up-to-date with the latest state value.</p>
<p>The traditional way of handling state in React is with the <code>useState</code> hook. It works great as long as your state changes are trivial. As the state change logic becomes more complex and if you need to manage multiple scenarios around it, <code>useState</code> may make things clumsy. This is where you should think about using the <code>useReducer</code> hook.</p>
<p><code>useReducer</code> is a standard hook from the React library. It accepts two primary parameters:</p>
<ul>
<li><code>initState</code>: the initial state value</li>
<li><code>reducer</code>: a JavaScript function that holds the state change logic based on an action (or trigger).</li>
</ul>
<p>The hook returns the following:</p>
<ul>
<li>A <code>state</code>: the current state value.</li>
<li>A <code>dispatch</code> function: a function that tells the respective reducer what to do next, and what data to act on.</li>
</ul>
<p>The image below explains each of the entities of the <code>useReducer</code> hook. If you want to learn about this hook in a greater depth, feel free to <a target="_blank" href="https://www.youtube.com/watch?v=PMyPyT8N4m8">check this out</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-27.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Anatomy of the useReducer Hook</em></p>
<h2 id="heading-how-to-create-actions">How to Create Actions</h2>
<p>The reducer function is the heart of the useReducer hook. It performs all the necessary logic to keep your application state updated and valid. </p>
<p>But how would the reducer function be aware of its task? Who would tell the reducer function what to do and what kind of data to work on? Here comes <code>actions</code>, an object that contains all the details for the reducer.</p>
<p>We define actions with types that indicate the stages a state change will occur in the reducer function. The same action object may also carry the application data(at times we call it payload) to pass to the reducer function when a component performs a dispatch.</p>
<p>We will now get started by creating some actions. We will define the types here. As our reducer needs to manage the inventory state on a data fetch, data fetch success, and data fetch error, we'll be defining actions for each of those.</p>
<p>Create a directory called <code>actions/</code> under the <code>src/</code> directory. Now create a file called <code>index.js</code> under the <code>src/actions/</code> directory with the following content:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> FETCH_ACTIONS = {
  <span class="hljs-attr">PROGRESS</span>: <span class="hljs-string">'progress'</span>,
  <span class="hljs-attr">SUCCESS</span>: <span class="hljs-string">'success'</span>,
  <span class="hljs-attr">ERROR</span>: <span class="hljs-string">'error'</span>,
}

<span class="hljs-keyword">export</span> { FETCH_ACTIONS };
</code></pre>
<p>We have defined three actions, PROGRESS, SUCCESS, and ERROR. Next, let's create the reducer.</p>
<h2 id="heading-how-to-create-an-inventory-reducer">How to Create an Inventory Reducer</h2>
<p>We need a reducer where we will keep all the state change logic. The same reducer will be passed to the <code>useReducer</code> hook later to get the current state value and dispatch the function to the component.</p>
<p>Create a directory called <code>reducers/</code> under the <code>src/</code>. Now, create a file called <code>inventoryReducers.js</code> under the <code>src/reducers/</code> directory.</p>
<p>Our reducer will need the actions because it has to work on state changes based on the actions. So, let's import the actions into the <code>inventoryReducers.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { FETCH_ACTIONS } <span class="hljs-keyword">from</span> <span class="hljs-string">"../actions"</span>
</code></pre>
<p>You can define an initial state in the reducer file. The <code>useReducer</code> hook needs a reducer and an initial state to give us the current state value, remember? Let's define an initial state.</p>
<p>We need to show a list of inventory items after getting a successful API response. While we are fetching the list of items by making an API call, we need to manage a loading data state. </p>
<p>In case there is any problem in fetching data, we need to report the error using the error state. So we can create an initial state with all these values as object properties.</p>
<p>Now, create an initialState variable with the following state object value assigned to it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">items</span>: [],
  <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>,
}
</code></pre>
<p>Next, let's create the reducer function. Create a function called <code>inventoryReducer</code> with the following code snippet:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> inventoryReducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {

  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> FETCH_ACTIONS.PROGRESS: {
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span>,
      }
    }

    <span class="hljs-keyword">case</span> FETCH_ACTIONS.SUCCESS: {
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">items</span>: action.data,
      }
    }

    <span class="hljs-keyword">case</span> FETCH_ACTIONS.ERROR: {
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">error</span>: action.error,
      }
    }

    <span class="hljs-attr">default</span>: {
      <span class="hljs-keyword">return</span> state;
    }      
  }

}
</code></pre>
<p>Let's understand the above code snippet. The <code>inventoryReducer</code> function takes two arguments, <code>state</code> and <code>action</code>. The reducer function works on the state based on the action type. For example,</p>
<ul>
<li>When it is a <code>PROGRESS</code> action, we want the <code>loading</code> value to be true.</li>
<li>For a <code>SUCCESS</code> action, we want to populate the <code>items</code> with the data received from the API response along with making the <code>loading</code> value as false.</li>
<li>For an <code>ERROR</code> action, we'll provide a value to the <code>error</code> property of the state.</li>
</ul>
<p>In any of the cases above, we do not mutate the state directly. Rather, we create a clone (a new reference of it using the <code>...</code> operator) of the state and then update its properties accordingly. Finally, we return the updated state for each of the actions. If the passed actions do not match any of the given types, we return back the state as it is.</p>
<p>Last, export the <code>inventoryReducer</code> function and the <code>initialState</code> object:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> {inventoryReducer, initialState};
</code></pre>
<p>Here is the complete code from the <code>inventoryReducers.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { FETCH_ACTIONS } <span class="hljs-keyword">from</span> <span class="hljs-string">"../actions"</span>

<span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">items</span>: [],
  <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>,
}

<span class="hljs-keyword">const</span> inventoryReducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {

  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> FETCH_ACTIONS.PROGRESS: {
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span>,
      }
    }

    <span class="hljs-keyword">case</span> FETCH_ACTIONS.SUCCESS: {
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">items</span>: action.data,
      }
    }

    <span class="hljs-keyword">case</span> FETCH_ACTIONS.ERROR: {
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">error</span>: action.error,
      }
    }

    <span class="hljs-attr">default</span>: {
      <span class="hljs-keyword">return</span> state;
    } 
  }

}

<span class="hljs-keyword">export</span> {inventoryReducer, initialState};
</code></pre>
<h2 id="heading-how-to-build-the-inventory-list-component">How to Build the Inventory List Component</h2>
<p>We will now create the inventory list component where we will use the reducer we created above.</p>
<p>Create a directory called <code>components/</code> under the <code>src/</code> directory. Now, create a file called <code>InventoryList.jsx</code> under the <code>stc/components/</code> directory.</p>
<p>First import the required things like:</p>
<ul>
<li>The <code>useReducer</code> hook where we will use the inventory reducer.</li>
<li>The <code>useEffect</code> hook to handle the async call with Axios.</li>
<li>The <code>inventory reducer</code> and the <code>initial state</code> we created a few minutes back.</li>
<li>The <code>actions</code>, as we need them to dispatch.</li>
<li>The <code>axios</code> for making async calls.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useReducer, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">import</span> { inventoryReducer, initialState } <span class="hljs-keyword">from</span> <span class="hljs-string">"../reducers/inventoryReducer"</span>;

<span class="hljs-keyword">import</span> { FETCH_ACTIONS } <span class="hljs-keyword">from</span> <span class="hljs-string">"../actions"</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
</code></pre>
<p>Now, create a function to define the component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> InventoryList = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(inventoryReducer, initialState);

  <span class="hljs-keyword">const</span> { items, loading, error} = state;

  <span class="hljs-keyword">return</span>(
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-2/5"</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Here,</p>
<ul>
<li>We have used the <code>useReducer</code> hook. We passed the <code>inventoryReducer</code> and the <code>initialState</code> to it as arguments to get the current <code>state</code> value and the <code>dispatch</code> function.</li>
<li>As we know the state object has the <code>items</code>, <code>loading</code>, and <code>error</code> as properties, we <code>destructure</code> them into our component. We will use them shortly.</li>
<li>The component returns an empty div that we will change as we proceed.</li>
</ul>
<p>Finally export the component as a default export like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> InventoryList;
</code></pre>
<h2 id="heading-how-to-use-axios-to-fetch-data-and-dispatch-it-to-the-reducer">How to Use Axios to Fetch Data and Dispatch it to the Reducer</h2>
<p>It's data fetching time! Data fetching by making an asynchronous call is a side effect you need to handle in your component. Copy and paste the <code>useEffect</code> code block inside the <code>InventoryList</code> function. </p>
<pre><code class="lang-js"><span class="hljs-comment">// -- The code above as it is</span>

<span class="hljs-keyword">const</span> InventoryList = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-comment">// --- The code above as it is</span>


  useEffect(<span class="hljs-function">() =&gt;</span> {
    dispatch({<span class="hljs-attr">type</span>: FETCH_ACTIONS.PROGRESS});

    <span class="hljs-keyword">const</span> getItems = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span>{
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">"http://localhost:3000/edibles"</span>);
        <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
          dispatch({<span class="hljs-attr">type</span>: FETCH_ACTIONS.SUCCESS, <span class="hljs-attr">data</span>: response.data});
        }
      } <span class="hljs-keyword">catch</span>(err){
        <span class="hljs-built_in">console</span>.error(err);
        dispatch({<span class="hljs-attr">type</span>: FETCH_ACTIONS.ERROR, <span class="hljs-attr">error</span>: err.message})
      }
    }

    getItems();

  }, []);

  <span class="hljs-comment">// --- The JSX return statement below as it is</span>
</code></pre>
<p>Let's understand the code flow:</p>
<ul>
<li>At the start of the <code>useEffect</code> callback, we dispatched a <code>PROGRESS</code> action. It invokes the reducer function with progress action type to turn the <code>loading</code> property value to true. We can use the loading property value in the JSX later to show a loading indicator.</li>
<li>Then we use Axios to make an asynchronous call using the API URL. On receiving the response, we check if it's a success, and in that case we dispatch a <code>SUCCESS</code> action along with the <code>items</code> data(remember, payload?) from response. This time the dispatcher will invoke the reducer with the success action to change the <code>items</code> and <code>loading</code> properties accordingly.</li>
<li>If there is an error, we dispatch an error action with the error message to update the state with the error information in the reducer.</li>
</ul>
<p>Each time we dispatch an action and update the state, we also get back the latest state value into our component. It's time to use the state value in the JSX to render the inventory item list.</p>
<h2 id="heading-lets-complete-the-jsx-part">Let's Complete the JSX Part</h2>
<p>The JSX part is fairly simple:</p>
<pre><code class="lang-js">
<span class="hljs-comment">// -- The code above as it is</span>

<span class="hljs-keyword">const</span> InventoryList = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-comment">// -- The code above as it is</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-2/5"</span>&gt;</span>
      {
        loading ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        ) : error ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{error}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        ) : (
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl my-4"</span>&gt;</span>Item List<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            {
              items.map((item) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col p-2 my-2 bg-gray-200 border rounded-md"</span> 
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'my-2 text-xl'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.name}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> {' '} {item.picture} of type <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.type}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
                    {' '} costs <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.price}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> INR/KG.
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mb-2 text-lg'</span>&gt;</span>
                    Available in Stock: <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.quantity}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              ))
            }

          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        )
      }

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> InventoryList;
</code></pre>
<p>Here's what's going on in the code:</p>
<ul>
<li>We show a <code>loading...</code> message if the loading property of the state is true. </li>
<li>We show the error message in case there's an error.</li>
<li>In neither of the cases, we iterate through the inventory items using the map function. Each of the items in the <code>items</code> array has information like picture, name, price, and more. We show this information in a meaningful way.</li>
</ul>
<p>Here is the complete code of the <code>InventoryList</code> component:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">import</span> { useReducer, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { inventoryReducer, initialState } <span class="hljs-keyword">from</span> <span class="hljs-string">"../reducers/inventoryReducer"</span>;
<span class="hljs-keyword">import</span> { FETCH_ACTIONS } <span class="hljs-keyword">from</span> <span class="hljs-string">"../actions"</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> InventoryList = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(inventoryReducer, initialState);

  <span class="hljs-keyword">const</span> { items, loading, error} = state;

  <span class="hljs-built_in">console</span>.log(items, loading, error);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    dispatch({<span class="hljs-attr">type</span>: FETCH_ACTIONS.PROGRESS});

    <span class="hljs-keyword">const</span> getItems = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span>{
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">"http://localhost:3000/edibles"</span>);
        <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
          dispatch({<span class="hljs-attr">type</span>: FETCH_ACTIONS.SUCCESS, <span class="hljs-attr">data</span>: response.data});
        }
      } <span class="hljs-keyword">catch</span>(err){
        <span class="hljs-built_in">console</span>.error(err);
        dispatch({<span class="hljs-attr">type</span>: FETCH_ACTIONS.ERROR, <span class="hljs-attr">error</span>: err.message})
      }
    }

    getItems();

  }, []);


  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-2/5"</span>&gt;</span>
      {
        loading ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        ) : error ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{error}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        ) : (
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl my-4"</span>&gt;</span>Item List<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            {
              items.map((item) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col p-2 my-2 bg-gray-200 border rounded-md"</span> 
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'my-2 text-xl'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.name}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> {' '} {item.picture} of type <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.type}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
                    {' '} costs <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.price}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> INR/KG.
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mb-2 text-lg'</span>&gt;</span>
                    Available in Stock: <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{item.quantity}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              ))
            }

          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        )
      }

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> InventoryList
</code></pre>
<h2 id="heading-how-to-use-the-inventory-list-in-the-app-component">How to Use the Inventory List in the App Component</h2>
<p>Now we have to let the <code>App</code> component know about the <code>InventoryList</code> component so that we can render it. Open the <code>App.jsx</code> file and replace its content with the following code snippet:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> InventoryList <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/InventoryList"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InventoryList</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>That's it. Make sure your application server is running. Now, access the app on your browser using the following URL <a target="_blank" href="http://localhost:5173/"><code>http://localhost:5173/</code></a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/image-28.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Final Output - Inventory List</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>I hope you enjoyed building this project and learning more about React. <a target="_blank" href="https://github.com/atapas/youtube/tree/main/react/27-inventory-useReducer-jsonserver-axios">Here is the source code</a> on my GitHub. Please feel free to extend the project by adding features like:</p>
<ul>
<li>Adding an item to the inventory</li>
<li>Editing an item from the inventory</li>
<li>Deleting an item from the inventory</li>
</ul>
<p>Hint: You need to create actions for each of these and enhance the reducer function to write state update logic to support these features. I hope you give it a try and if you do so, let me know (my contacts are mentioned below). </p>
<p>That's all for now. I also publish meaningful posts on my <a target="_blank" href="https://blog.greenroots.info/">GreenRoots Blog</a>, and I think you'll find them helpful, too.</p>
<p>Let's connect.</p>
<ul>
<li>I am an educator on my YouTube channel, <code>tapaScript</code>. Please <a target="_blank" href="https://www.youtube.com/tapasadhikary?sub_confirmation=1">SUBSCRIBE</a> to the channel if you want to learn JavaScript, ReactJS, Next.js, Node.js, Git, and all about Web Development fundamentally.</li>
<li><a target="_blank" href="https://twitter.com/tapasadhikary">Follow me on X (Twitter</a>) or <a target="_blank" href="https://www.linkedin.com/in/tapasadhikary/">LinkedIn</a> if you don't want to miss the daily dose of Web Development and Programming Tips.</li>
<li>Find all my public speaking talks <a target="_blank" href="https://www.tapasadhikary.com/talks">here</a>.</li>
<li>Check out and follow my Open Source work on <a target="_blank" href="https://github.com/atapas">GitHub</a>.</li>
</ul>
<p>See you soon with my next article. Until then, please take care of yourself, and stay happy.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript Get Request – How to Make an HTTP Request in JS ]]>
                </title>
                <description>
                    <![CDATA[ When building applications, you will have to interact between the backend and frontend to get, store, and manipulate data. This interaction between your frontend application and the backend server is possible through HTTP requests. There are five pop... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/javascript-get-request-tutorial/</link>
                <guid isPermaLink="false">66d45fd9d1ffc3d3eb89de0e</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ http ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Thu, 15 Dec 2022 19:05:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/12/cover-template--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When building applications, you will have to interact between the backend and frontend to get, store, and manipulate data.</p>
<p>This interaction between your frontend application and the backend server is possible through HTTP requests.</p>
<p>There are five popular HTTP methods you can use to make requests and interact with your servers. One HTTP method is the GET method, which can retrieve data from your server.</p>
<p>This article will teach you how to request data from your servers by making a GET request. You will learn the popular methods that exist currently and some other alternative methods.</p>
<p>For this guide, we'll retrieve posts from the free <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSON Placeholder posts API</a>.</p>
<p>There are two popular methods you can easily use to make HTTP requests in JavaScript. These are the Fetch API and Axios.</p>
<h2 id="heading-how-to-make-a-get-request-with-the-fetch-api">How to Make a GET Request with the Fetch API</h2>
<p>The Fetch API is a built-in JavaScript method for retrieving resources and interacting with your backend server or an API endpoint. Fetch API is built-in and does not require installation into your project.</p>
<p>Fetch API accepts one mandatory argument: the API endpoint/URL. This method also accepts an <strong>option</strong> argument, which is an optional object when making a GET request <strong>because it is the default request</strong>.</p>
<pre><code class="lang-js">  fetch(url, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"GET"</span> <span class="hljs-comment">// default, so we can ignore</span>
  })
</code></pre>
<p>Let’s create a GET request to get a post from the <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSON Placeholder posts API</a>.</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>)
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">json</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(json));
</code></pre>
<p>This will return a single post which you can now store in a variable and use within your project.</p>
<blockquote>
<p>Note: For other methods, such as POST and DELETE, you need to attach the method to the options array.</p>
</blockquote>
<h2 id="heading-how-to-make-a-get-request-with-axios">How to Make a GET Request with Axios</h2>
<p>Axios is an HTTP client library. This library is based on promises that simplify sending asynchronous HTTP requests to REST endpoints. We will send a GET request to the JSONPlaceholder Posts API endpoint.</p>
<p>Axios, unlike the Fetch API, is not built-in. This means you need to install Axios into your JavaScript project.</p>
<p>To install a dependency into your JavaScript project, you will first initialize a new <code>npm</code> project by running the following command in your terminal:</p>
<pre><code class="lang-js">$ npm init -y
</code></pre>
<p>And now you can install Axios to your project by running the following command:</p>
<pre><code class="lang-js">$ npm install axios
</code></pre>
<p>Once Axios is successfully installed, you can create your GET request. This is quite similar to the Fetch API request. You will pass the API endpoint/URL to the <code>get()</code> method, which will return a promise. You can then handle the promise with the <code>.then()</code> and <code>.catch()</code> methods.</p>
<pre><code class="lang-js">axios.get(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>)
.then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(response.data))
.catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(error));
</code></pre>
<blockquote>
<p><strong>Note:</strong> The major difference is that, for Fetch API, you first convert the data to JSON, while Axios returns your data directly as JSON data.</p>
</blockquote>
<p>At this point, you have learned how to make a GET HTTP request with Fetch API and Axios. But there are some other methods that still exist. Some of these methods are <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a> and jQuery.</p>
<h2 id="heading-how-to-make-a-get-request-with-xmlhttprequest">How to Make a GET Request with <code>XMLHttpRequest</code></h2>
<p>You can use the XMLHttpRequest object to interact with servers. This method can request data from a web server’s API endpoint/URL without doing a full page refresh.</p>
<blockquote>
<p><strong>Note:</strong> All modern browsers have a built-in XMLHttpRequest object to request data from a server.</p>
</blockquote>
<p>Let’s perform the same request with the XMLHttpRequest by creating a new XMLHttpRequest object. You will then open a connection by specifying the request type and endpoint (the URL of the server), then you'll send the request, and finally listen to the server’s response.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> xhr = <span class="hljs-keyword">new</span> XMLHttpRequest();
xhr.open(<span class="hljs-string">"GET"</span>, <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>);
xhr.send();
xhr.responseType = <span class="hljs-string">"json"</span>;
xhr.onload = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (xhr.readyState == <span class="hljs-number">4</span> &amp;&amp; xhr.status == <span class="hljs-number">200</span>) {
    <span class="hljs-built_in">console</span>.log(xhr.response);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Error: <span class="hljs-subst">${xhr.status}</span>`</span>);
  }
};
</code></pre>
<p>In the above code, a new XMLHttpRequest object is created and stored in a variable called <code>xhr</code>. You can now access all its objects using the variable, such as the <code>.open()</code> method, when you specify the request type (GET) and the endpoint/URL where you want to request data.</p>
<p>Another method you will use is <code>.send()</code>, which sends the request to the server. You can also specify the format in which the data will be returned using the <code>responseType</code> method. At this point, the GET request is sent, and all you have to do is listen to its response using the <code>onload</code> event listener.</p>
<p>If the client's state is done (<strong>4),</strong> and the status code is successful (<strong>200)</strong>, then the data will be logged to the console. Otherwise, an error message showing the error status will appear.</p>
<h2 id="heading-how-to-make-a-get-request-with-jquery">How to Make a GET Request with jQuery</h2>
<p>Making HTTP requests in jQuery is relatively straightforward and similar to the Fetch API and Axios. To make a GET request, you will first install jQuery or make use of its CDN in your project:</p>
<pre><code class="lang-js">&lt;script src=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.2/jquery.min.js"</span> integrity=<span class="hljs-string">"sha512-tWHlutFnuG0C6nQRlpvrEhE4QpkG1nn2MOUMWmUeRePl4e3Aki0VB6W1v3oLjFtd0hVOtRQ9PHpSfN6u6/QXkQ=="</span> crossorigin=<span class="hljs-string">"anonymous"</span> referrerpolicy=<span class="hljs-string">"no-referrer"</span>&gt;&lt;/script&gt;
</code></pre>
<p>With jQuery, you can access the GET method <code>$.get()</code>, which takes in two parameters, the API endpoint/URL and a callback function that runs when the request is successful.</p>
<pre><code class="lang-js">$.get(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>, <span class="hljs-function">(<span class="hljs-params">data, status</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(data);
});
</code></pre>
<blockquote>
<p><strong>Note:</strong> In the callback function, you have access to the request's <strong>data</strong> and the request's <strong>status</strong>.</p>
</blockquote>
<p>You can also use the jQuery AJAX Method, which is quite different and can be used to make asynchronous requests:</p>
<pre><code class="lang-js">$.ajax({
  <span class="hljs-attr">url</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>,
  <span class="hljs-attr">type</span>: <span class="hljs-string">"GET"</span>,
  <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
    <span class="hljs-built_in">console</span>.log(data);
  }
});
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this article, you have learned how to make the HTTP GET request in JavaScript. You might now begin to think — which method should I use?</p>
<p>If it’s a new project, you can choose between the Fetch API and Axios. Also, if you want to consume basic APIs for a small project, there is no need to use Axios, which demands installing a library.</p>
<p>Have fun coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Consume REST APIs in React – a Beginner's Guide ]]>
                </title>
                <description>
                    <![CDATA[ React is a popular frontend library that developers use to create applications. And you will need to integrate APIs into your React application at some point if you want to build production-ready apps. Every developer who wants to build modern, robus... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-consume-rest-apis-in-react/</link>
                <guid isPermaLink="false">66d45f9351f567b42d9f8481</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Tue, 21 Jun 2022 15:35:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/06/cover-template-2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React is a popular frontend library that developers use to create applications. And you will need to integrate APIs into your React application at some point if you want to build production-ready apps.</p>
<p>Every developer who wants to build modern, robust web applications with React must understand how to consume APIs to fetch data into their React applications.</p>
<p>In this beginners guide, you will learn how to consume RESTful API in React, including fetching, deleting, and adding data. We'll also go over the two main ways to consume RESTful APIs and how to use them with React hooks.</p>
<h3 id="heading-heres-an-interactive-scrim-about-consuming-rest-apis-in-react-more-scrims-below">Here's an interactive scrim about consuming REST APIs in React (more scrims below):</h3>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/coc6f42838bab19b28a86cca1?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-what-is-a-rest-api">What is a REST API?</h2>
<p>If you've ever spent any time programming or researching programming, you've likely come across the term "API."</p>
<p>API stands for Application Programming Interface. It is a medium that allows different applications to communicate programmatically with one another and return a response in real time.</p>
<p>Roy Fielding defined REST in 2000 as an architectural style and methodology commonly used in the development of internet services, such as distributed hypermedia systems. It is an acronym that stands for "REpresentational State Transfer."</p>
<p>When a request is made via a REST API, it sends a representation of the resource's current state to the requester or endpoint. This state representation can take the form of JSON (JavaScript Object Notation), XML, or HTML.</p>
<p>JSON is the most widely used file format because it is language-independent and can be read by both humans and machines.</p>
<p><strong>For example:</strong></p>
<pre><code class="lang-json">[
   {
      <span class="hljs-attr">"userId"</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"sunt excepturi"</span>,
      <span class="hljs-attr">"body"</span>: <span class="hljs-string">"quia et suscipit\nsuscipit recusandae consequuntur "</span>
   },
   {
      <span class="hljs-attr">"userId"</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"qui est esse"</span>,
      <span class="hljs-attr">"body"</span>: <span class="hljs-string">"est rerum tempore vitae\nsequi sint nihil"</span>
   }
]
</code></pre>
<h2 id="heading-how-to-consume-rest-apis-in-react">How to Consume REST API’s in React</h2>
<p>You can consume REST APIs in a React application in a variety of ways, but in this guide, we will look at two of the most popular approaches: Axios (a promise-based HTTP client) and Fetch API (a browser in-built web API).</p>
<p><strong>Note:</strong> To fully comprehend this guide, you should be familiar with JavaScript, React, and React hooks, as they are central to it.</p>
<p>Before we get into how to consume APIs, it's important to understand that consuming APIs in React is very different from how it's done in JavaScript. This is because these requests are now done in a React Component.</p>
<p>In our case, we'll be using functional components, which means that we need to use two major React Hooks:</p>
<ul>
<li><strong>useEffect Hook:</strong> In React, we perform API requests within the <code>useEffect()</code> hook. It either renders immediately when the app mounts or after a specific state is reached. This is the general syntax we'll use:</li>
</ul>
<pre><code class="lang-bash">useEffect(() =&gt; {
    // data fetching here
}, []);
</code></pre>
<ul>
<li><strong>useState Hook:</strong> When we request data, we must prepare a state in which the data will be stored when it is returned. We can save it in a state management tool such as Redux or in a context object. To keep things simple, we'll store the returned data in the React local state.</li>
</ul>
<pre><code class="lang-bash">const [posts, setPosts] = useState([]);
</code></pre>
<p>Let's now get into the meat of this guide, where we'll learn how to get, add, and delete data using the <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSONPlaceholder posts API</a>. This knowledge is applicable to any type of API, as this guide is intended for beginners.</p>
<h2 id="heading-how-to-consume-apis-using-the-fetch-api">How to Consume APIs Using The Fetch API</h2>
<p>The Fetch API is a JavaScript built-in method for retrieving resources from a server or an API endpoint. It's built-in, so you don't need to install any dependencies or packages.</p>
<p>The <code>fetch()</code> method requires a mandatory argument, which is the path or URL to the resource you want to fetch. Then it returns a Promise so you can handle success or failure using the <code>then()</code> and <code>catch()</code> methods.</p>
<p>A basic fetch request is very simple to write and looks like the below code. We are simply fetching data from a URL that returns data as JSON and then logging it to the console:</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>)
   .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
   .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(data));
</code></pre>
<p>The default response is usually a regular HTTP response rather than the actual JSON, but we can get our output as a JSON object by using the response's json() method.</p>
<h3 id="heading-how-to-perform-a-get-request-in-react-with-fetch-api">How to Perform a GET Request in React With Fetch API</h3>
<p>You can use the HTTP GET method to request data from an endpoint.</p>
<p>As previously stated, the Fetch API accepts one mandatory argument, which is true. It also accepts an option argument, which is optional, especially when using the GET method, which is the default. But for other methods such as POST and DELETE, you'll need to attach the method to the options array:</p>
<pre><code class="lang-js">fetch(url, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"GET"</span> <span class="hljs-comment">// default, so we can ignore</span>
})
</code></pre>
<p>So far, we've learned how things work, so let's put everything we've learned together and perform a get request to fetch data from our API.</p>
<p>Again, we'll be using the <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">free online API JSONPlaceholder</a> to fetch a list of posts into our application:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);
   useEffect(<span class="hljs-function">() =&gt;</span> {
      fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>)
         .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
         .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(data);
            setPosts(data);
         })
         .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(err.message);
         });
   }, []);

<span class="hljs-keyword">return</span> (
   <span class="hljs-comment">// ... consume here</span>
);
};
</code></pre>
<p>We created a state in the preceding code to store the data we will retrieve from the API so that we can consume it later in our application. We also set the default value to an empty array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);
</code></pre>
<p>The major operation then occurred in the useEffect state, so that the data/posts are fetched as soon as the application loads. The fetch request yields a promise, which we can either accept or reject:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
   fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>).then(
      <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(response)
   );
}, []);
</code></pre>
<p>This response contains a large amount of data, such as the status code, text, and other information that we'll need to have to handle errors later.</p>
<p>So far, we've handled a resolve using <code>.then()</code>, but it returned a response object, which isn't what we want. So we need to resolve the Response object to JSON format using the <code>json()</code> method. This also returns a promise for us to get the actual data using the second <code>.then()</code>.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
   fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
         <span class="hljs-built_in">console</span>.log(data);
         setPosts(data);
      });
}, []);
</code></pre>
<p>If we look at the console, we'll see that we've retrieved 10 posts from our API, which we've also set to the state we specified earlier.</p>
<p>This is not complete because we have only handled the promise's resolve and not the promise's rejection, which we'll handle using the <code>.catch()</code> method:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
   fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
         <span class="hljs-built_in">console</span>.log(data);
         setPosts(data);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
         <span class="hljs-built_in">console</span>.log(err.message);
      });
}, []);
</code></pre>
<p>So far we have seen how to perform a <code>GET</code> request. This can be consumed easily into our application by looping through our array:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
<span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">return</span> (
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"posts-container"</span>&gt;</span>
      {posts.map((post) =&gt; {
         return (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-card"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-title"</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-body"</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"delete-btn"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
               <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
         );
      })}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-how-to-perform-a-post-request-in-react-with-fetch-api">How to Perform a POST Request in React With Fetch API</h3>
<p>You can use the HTTP <code>POST</code> method to send data to an endpoint. It works similarly to the <code>GET</code> request, the main difference being that you need to add the method and two additional parameters to the optional object:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> addPosts = <span class="hljs-keyword">async</span> (title, body) =&gt; {
<span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>, {
<span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
<span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
   <span class="hljs-attr">title</span>: title,
   <span class="hljs-attr">body</span>: body,
   <span class="hljs-attr">userId</span>: <span class="hljs-built_in">Math</span>.random().toString(<span class="hljs-number">36</span>).slice(<span class="hljs-number">2</span>),
}),
<span class="hljs-attr">headers</span>: {
   <span class="hljs-string">'Content-type'</span>: <span class="hljs-string">'application/json; charset=UTF-8'</span>,
},
})
.then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
.then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
   setPosts(<span class="hljs-function">(<span class="hljs-params">posts</span>) =&gt;</span> [data, ...posts]);
   setTitle(<span class="hljs-string">''</span>);
   setBody(<span class="hljs-string">''</span>);
})
.catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
   <span class="hljs-built_in">console</span>.log(err.message);
});
};
</code></pre>
<p>The major parameters that might appear strange are the body and header.</p>
<p>The body holds the data we want to pass into the API, which we must first stringify because we are sending data to a web server. The header tells us the type of data, which is always the same when consuming REST API's. We also set the state to hold the new data and distribute the remaining data into the array.</p>
<p>Looking at the <code>addPost()</code> method we created, it expects these data from a form or whatever. In our case, I created a form, obtained the form data via states, and then added it to the method when the form was submitted:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
<span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
<span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">const</span> addPosts = <span class="hljs-keyword">async</span> (title, body) =&gt; {
   <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
         <span class="hljs-attr">title</span>: title,
         <span class="hljs-attr">body</span>: body,
         <span class="hljs-attr">userId</span>: <span class="hljs-built_in">Math</span>.random().toString(<span class="hljs-number">36</span>).slice(<span class="hljs-number">2</span>),
      }),
      <span class="hljs-attr">headers</span>: {
         <span class="hljs-string">'Content-type'</span>: <span class="hljs-string">'application/json; charset=UTF-8'</span>,
      },
   })
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
         setPosts(<span class="hljs-function">(<span class="hljs-params">posts</span>) =&gt;</span> [data, ...posts]);
         setTitle(<span class="hljs-string">''</span>);
         setBody(<span class="hljs-string">''</span>);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
         <span class="hljs-built_in">console</span>.log(err.message);
      });
};

<span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
   e.preventDefault();
   addPosts(title, body);
};    

<span class="hljs-keyword">return</span> (
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"add-post-container"</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{title}</span>
               <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTitle(e.target.value)}
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">""</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">""</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"8"</span> 
               <span class="hljs-attr">value</span>=<span class="hljs-string">{body}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setBody(e.target.value)} 
            &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Add Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
         <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {/* ... */}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-how-to-perform-a-delete-request-in-react-with-fetch-api">How to Perform a DELETE Request in React With Fetch API</h3>
<p>You can use the HTTP <code>DELETE</code> method to remove data from an endpoint. It works similarly to the <code>GET</code> request, the main difference being the addition of the method:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> deletePost = <span class="hljs-keyword">async</span> (id) =&gt; {
<span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://jsonplaceholder.typicode.com/posts/<span class="hljs-subst">${id}</span>`</span>, {
   <span class="hljs-attr">method</span>: <span class="hljs-string">'DELETE'</span>,
}).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
   <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
      setPosts(
         posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> post.id !== id;
         })
      );
   } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">return</span>;
   }
});
};
</code></pre>
<p>This gets triggered when the button is clicked, and we get the <code>id</code> of the specific post in which the button was clicked. Then we remove that data from the entire retuned data.</p>
<p>This will be removed from the API but not immediately from the UI, which is why we have added a filter to remove the data as well. For each item in the loop, your delete button will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
<span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">return</span> (
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"posts-container"</span>&gt;</span>
      {posts.map((post) =&gt; {
         return (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-card"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>
               {/* ... */}
               <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"delete-btn"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deletePost(post.id)}&gt;
                     Delete
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
               <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>    
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
         );
      })}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-how-to-use-asyncawait-in-fetch-api">How to Use Async/Await in Fetch API</h3>
<p>So far, we've seen how to make fetch requests normally using the promise syntax, which can be confusing at times. Then comes the chaining. We can avoid the <code>.then()</code> chaining by using Async/await and write more readable code.</p>
<p>To use async/await, first call <code>async</code> in the function. Then when making a request and expecting a response, add the <code>await</code> syntax in front of the function to wait until the promise settles with the result.</p>
<p>When we use async/await, all of our Fetch requests will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   <span class="hljs-comment">// GET with fetch API</span>
   useEffect(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
         <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
            <span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>
         );
         <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
         <span class="hljs-built_in">console</span>.log(data);
         setPosts(data);
      };
      fetchPost();
   }, []);

   <span class="hljs-comment">// Delete with fetchAPI</span>
   <span class="hljs-keyword">const</span> deletePost = <span class="hljs-keyword">async</span> (id) =&gt; {
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> fetch(
         <span class="hljs-string">`https://jsonplaceholder.typicode.com/posts/<span class="hljs-subst">${id}</span>`</span>,
         {
            <span class="hljs-attr">method</span>: <span class="hljs-string">'DELETE'</span>,
         }
      );
      <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
         setPosts(
            posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
               <span class="hljs-keyword">return</span> post.id !== id;
            })
         );
      } <span class="hljs-keyword">else</span> {
         <span class="hljs-keyword">return</span>;
      }
   };

   <span class="hljs-comment">// Post with fetchAPI</span>
   <span class="hljs-keyword">const</span> addPosts = <span class="hljs-keyword">async</span> (title, body) =&gt; {
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>, {
         <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
         <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
            <span class="hljs-attr">title</span>: title,
            <span class="hljs-attr">body</span>: body,
            <span class="hljs-attr">userId</span>: <span class="hljs-built_in">Math</span>.random().toString(<span class="hljs-number">36</span>).slice(<span class="hljs-number">2</span>),
         }),
         <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">'Content-type'</span>: <span class="hljs-string">'application/json; charset=UTF-8'</span>,
         },
      });
      <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> response.json();
      setPosts(<span class="hljs-function">(<span class="hljs-params">posts</span>) =&gt;</span> [data, ...posts]);
      setTitle(<span class="hljs-string">''</span>);
      setBody(<span class="hljs-string">''</span>);
   };

   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      addPosts(title, body);
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h4 id="heading-heres-an-interactive-scrim-to-walk-you-through-this">Here's an interactive scrim to walk you through this:</h4>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/co1af4d8f8db412c467e20af0?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h3 id="heading-how-to-handle-errors-with-fetch-api">How to Handle Errors with Fetch API</h3>
<p>In this section, we'll look at how to handle errors both traditionally and with async/await.</p>
<p>We can use the response data to handle errors in the Fetch API, or we can use the try/catch statement when using async/await.</p>
<p>Let's look at how we can do this typically in Fetch API:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> fetchPost = <span class="hljs-function">() =&gt;</span> {
fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>)
   .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (!response.ok) {
         <span class="hljs-keyword">throw</span> <span class="hljs-built_in">Error</span>(response.statusText);
      }
      <span class="hljs-keyword">return</span> response.json();
   })
   .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(data);
      setPosts(data);
   })
   .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(err.message);
   });
};
</code></pre>
<p>You can read more about Fetch API errors <a target="_blank" href="https://www.tjvantoll.com/2015/09/13/fetch-and-errors/">here</a>.</p>
<p>And for async/await we can use the <code>try</code> and <code>catch</code> like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
         <span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>
      );
      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
      setPosts(data);
   } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
   }
};
</code></pre>
<h2 id="heading-how-to-consume-apis-using-axios">How to Consume APIs Using Axios</h2>
<p>Axios is an HTTP client library based on promises that makes it simple to send asynchronous HTTP requests to REST endpoints. This endpoint in our case is the JSONPlaceholder Posts API, to which we will make <code>GET</code>, <code>POST</code>, and <code>DELETE</code> requests.</p>
<h4 id="heading-heres-an-interactive-scrim-thatll-walk-you-through-the-steps-as-you-read">Here's an interactive scrim that'll walk you through the steps as you read:</h4>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/cob6540b4a1ad315f83abd56d?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h3 id="heading-how-to-install-and-configure-an-axios-instance">How to Install and Configure an Axios Instance</h3>
<p>Axios, unlike the Fetch API, is not built-in, so we will need to incorporate it into our project in order to use it.</p>
<p>You can add Axios to your project by running the following command:</p>
<pre><code class="lang-js">npm install axios
</code></pre>
<p>Once you've successfully installed Axios, we can proceed to create an instance, which is optional but recommended as it saves us from unnecessary repetition.</p>
<p>To create an instance, we use the <code>.create()</code> method, which we can use to specify information such as the URL and possibly headers:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> client = axios.create({
   <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span> 
});
</code></pre>
<h3 id="heading-how-to-perform-a-get-request-in-react-with-axios">How to Perform a GET Request in React With Axios</h3>
<p>We will use the instance we declared earlier for to perform the GET request. All we will do is set the parameters, if any, and get the response as JSON by default.</p>
<p>Unlike the Fetch API method, no option is required to declare the method. We simply attach the method to the instance and query it.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
   client.get(<span class="hljs-string">'?_limit=10'</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPosts(response.data);
   });
}, []);
</code></pre>
<h3 id="heading-how-to-perform-a-post-request-in-react-with-axios">How to Perform a POST Request in React With Axios</h3>
<p>As previously stated, you can use the <code>POST</code> method to send data to an endpoint. It functions similarly to the <code>GET</code> request, with the main difference being the requirement to include the method and an option to hold the data we are sending in:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> addPosts = <span class="hljs-function">(<span class="hljs-params">title, body</span>) =&gt;</span> {
   client
      .post(<span class="hljs-string">''</span>, {
         <span class="hljs-attr">title</span>: title,
         <span class="hljs-attr">body</span>: body,
      })
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
         setPosts(<span class="hljs-function">(<span class="hljs-params">posts</span>) =&gt;</span> [response.data, ...posts]);
      });
};
</code></pre>
<h3 id="heading-how-to-perform-a-delete-request-in-react-with-axios">How to Perform a DELETE Request in React With Axios</h3>
<p>We can perform delete requests using the delete method, which gets the <code>id</code> and deletes it from the API. We'll also use the filter method to remove it from the UI, as we did with the Fetch API method:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> deletePost = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
   client.delete(<span class="hljs-string">`<span class="hljs-subst">${id}</span>`</span>);
   setPosts(
      posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
         <span class="hljs-keyword">return</span> post.id !== id;
      })
   );
};
</code></pre>
<h3 id="heading-how-to-use-asyncawait-in-axios">How to Use Async/Await in Axios</h3>
<p>So far, we've seen how to make Axios requests using the promise syntax. But now let's see how we can use async/await to write less code and avoid the <code>.then()</code> chaining.</p>
<p>When we use async/await, all of our Axios requests will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   <span class="hljs-comment">// GET with Axios</span>
   useEffect(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
         <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'?_limit=10'</span>);
         setPosts(response.data);
      };
      fetchPost();
   }, []);

   <span class="hljs-comment">// Delete with Axios</span>
   <span class="hljs-keyword">const</span> deletePost = <span class="hljs-keyword">async</span> (id) =&gt; {
      <span class="hljs-keyword">await</span> client.delete(<span class="hljs-string">`<span class="hljs-subst">${id}</span>`</span>);
      setPosts(
         posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> post.id !== id;
         })
      );
   };

   <span class="hljs-comment">// Post with Axios</span>
   <span class="hljs-keyword">const</span> addPosts = <span class="hljs-keyword">async</span> (title, body) =&gt; {
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">''</span>, {
         <span class="hljs-attr">title</span>: title,
         <span class="hljs-attr">body</span>: body,
      });
      setPosts(<span class="hljs-function">(<span class="hljs-params">posts</span>) =&gt;</span> [response.data, ...posts]);
   };

   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      addPosts(title, body);
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h3 id="heading-how-to-handle-errors-with-axios">How to Handle Errors with Axios</h3>
<p>For promise-based Axios requests, we can use the<code>.then()</code> and.<code>catch (</code>) methods, but for async/await, we can use the <code>try...catch</code> block. This is very similar to how we implemented the Fetch API, and the <code>try...catch</code> block will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'?_limit=10'</span>);
      setPosts(response.data);
   } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
   }
};
</code></pre>
<p>You can read more about handling errors with Axios <a target="_blank" href="https://stackabuse.com/handling-errors-with-axios/">here</a>.</p>
<h2 id="heading-fetch-api-vs-axios">Fetch API vs Axios</h2>
<p>You may have noticed some differences, but let's put them in a handy table so we can compare Fetch and Axios properly.</p>
<p>These distinctions will help you decide which method to use for a specific project. Among these distinctions are:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Axios</td><td>Fetch</td></tr>
</thead>
<tbody>
<tr>
<td>Axios is a standalone third-party package that is simple to install.</td><td>Fetch is built into most modern browsers. <strong>No installation</strong> is required as such.</td></tr>
<tr>
<td>Axios uses the <strong>data</strong> property.</td><td>Fetch uses the <strong>body</strong> property.</td></tr>
<tr>
<td>Axios data contains the <strong>object</strong>.</td><td>Fetch’s body has to be <strong>stringified</strong>.</td></tr>
<tr>
<td>When the status is 200 and the statusText is 'OK,' the Axios request is accepted.</td><td>Fetch request is ok when <strong>response object contains the ok property</strong>.</td></tr>
<tr>
<td>Axios performs <strong>automatic transforms of JSON data</strong>.</td><td>Fetch is a <strong>two-step process</strong> when handling JSON data- first, to make the actual request; second, to call the .json() method on the response.</td></tr>
<tr>
<td>Axios allows <strong>cancelling request and request timeout</strong>.</td><td>Fetch does not.</td></tr>
<tr>
<td>Axios has <strong>built-in support for download progress</strong>.</td><td>Fetch does not support upload progress.</td></tr>
<tr>
<td>Axios has <strong>wide browser support</strong>.</td><td>Fetch is only compatible with Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.1+. (This is known as Backward Compatibility).</td></tr>
</tbody>
</table>
</div><h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, we learned how to consume REST APIs in React using either the Fetch API or Axios.</p>
<p>This will help you get started with API consumption in React, and from there you will be able to consume data in more complex ways and manipulate your APIs however you choose.</p>
<p>Embark on a journey of learning! <a target="_blank" href="https://joelolawanle.com/contents">Browse 200+ expert articles on web development</a>. Check out <a target="_blank" href="https://joelolawanle.com/posts">my blog</a> for more captivating content from me.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Axios React – How to Make Get, Post, and Delete API Requests ]]>
                </title>
                <description>
                    <![CDATA[ Axios is an HTTP client library based on promises. It makes sending asynchronous HTTP requests to REST endpoints easier and helps you perform CRUD operations. This REST endpoint/API could be an external API like the Google API, GitHub API, and so on ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/axios-react-how-to-make-get-post-and-delete-api-requests/</link>
                <guid isPermaLink="false">66d45f638812486a37369cd7</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Tue, 17 May 2022 16:12:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/cover-template.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><a target="_blank" href="https://axios-http.com/">Axios</a> is an HTTP client library based on promises. It makes sending asynchronous HTTP requests to REST endpoints easier and helps you perform CRUD operations.</p>
<p>This REST endpoint/API could be an external API like the Google API, GitHub API, and so on – or it could be your own backend Node.js server.</p>
<p>In this guide, we will learn how to make Axios GET, POST, and DELETE API requests in React. This simply refers to how we retrieve data from an API, add data to the API, and then delete data from our API.</p>
<p>Get, Post, and Delete API requests are among the most common daily requests made by developers. After all, we will always need to fetch data to display on our application or perform certain operations, as well as add and delete data to/from our API.</p>
<h3 id="heading-heres-an-interactive-scrim-about-how-to-make-axios-get-post-and-delete-api-requests-in-react">Here's an interactive scrim about how to make Axios GET, POST, and DELETE API requests in React:</h3>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/co6e84267986fe1194cb9ac07?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-why-axios">Why Axios?</h2>
<p>The next question you might have is why we are using Axios, given that we will need to install an additional library. Here are some reasons:</p>
<ul>
<li><p>Axios uses <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a> under the hood, and it is widely supported by most browsers, including older ones like Internet Explorer 11. Fetch(), on the other hand, is only compatible with Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.3+ (you can see the full compatibly table on <a target="_blank" href="https://caniuse.com/fetch">CanIUse.com</a>).</p>
</li>
<li><p>When sending requests, Axios automatically signifies the data, unlike fetch(), which requires us to do it manually.</p>
</li>
<li><p>Unlike the Fetch API, which requires you to check the status code and throw the error yourself, Axios has better error handling and can throw 400 and 500 range errors.</p>
</li>
</ul>
<h2 id="heading-how-to-get-started-with-axios-in-react">How to Get Started with Axios in React</h2>
<p>To get started with Axios in your React application, first install React into your project with the following command:</p>
<pre><code class="lang-bash">npm install axios
</code></pre>
<p>Once that is completed, we will be using the <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSONPlacholder Posts API</a> to learn how to fetch these posts into our React application, add new posts, and finally delete a specific post with Axios.</p>
<p>Because this is a React application, we will use React hooks to gain access to states and other features. The hooks we'll be using are <code>useEffect()</code> and <code>useState()</code>.</p>
<p>Essentially, we'll use the <code>useEffect()</code> hook to fetch posts as soon as the app renders/mounts, while the <code>useState()</code> hook will help us create a local storage for our data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/image-89.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-the-axios-instance">How to Create the Axios Instance</h3>
<p>Once you've successfully installed Axios, it's a good idea to create an Axios instance. It's not required, but it saves us time.</p>
<p>To create an instance, we'll use the <code>.create()</code> method, which lets us specify information such as the URL and possibly headers:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> client = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span> 
});
</code></pre>
<h2 id="heading-how-to-make-a-get-request-with-axios-in-react">How to Make a GET Request with Axios in React</h2>
<p>You can use GET requests to get data from an endpoint, and it'll happen as soon as the app renders thanks to the <code>useEffect()</code> hook.</p>
<p>We'll use the variable and then attach the <code>.get()</code> method to make a GET request to our endpoint/API. Then we'll use a <code>.then()</code> callback to get back all the response data, because we already have an Axios instance that holds the <code>baseURL</code> assigned to a variable (client).</p>
<p>Using the <code>.data</code> property, we obtain the response data, which is the actual data from the response object.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   useEffect(<span class="hljs-function">() =&gt;</span> {
      client.get(<span class="hljs-string">'?_limit=10'</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
         setPosts(response.data);
      });
   }, []);

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>We set the data to the state we created, so it can be consumed within our application.</p>
<h3 id="heading-how-to-consume-a-get-request">How to Consume a GET Request</h3>
<p>After successfully implementing the GET request, the next step is to consume the data stored in the <code>posts</code> state.</p>
<p>Because we are querying for an array of ten posts, we will have to loop through this state to get these ten posts into our application:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All Posts 📫<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    {posts.map((post) =&gt; {
       return (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-card"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>
             <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-title"</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
             <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-body"</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
             <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"delete-btn"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
             <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       );
    })}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);

<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="heading-how-to-make-a-post-request-with-axios-in-react">How to Make a POST Request with Axios in React</h2>
<p>You use a POST request to send data to an endpoint. It works similarly to a GET request, except that the function created to perform this task will be triggered when the form is submitted or otherwise.</p>
<p>This takes an object to send the data in and also adds the data to the state by spreading the previous data and then adding the new data:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   <span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      addPosts(title, body);
   };

   <span class="hljs-keyword">const</span> addPosts = <span class="hljs-function">(<span class="hljs-params">title, body</span>) =&gt;</span> {
      client
         .post(<span class="hljs-string">''</span>, {
            <span class="hljs-attr">title</span>: title,
            <span class="hljs-attr">body</span>: body,
         })
         .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
            setPosts([response.data, ...posts]);
         });
      setTitle(<span class="hljs-string">''</span>);
      setBody(<span class="hljs-string">''</span>);
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>When the form is submitted, we call the <code>handleSubmit()</code> function, which prevents the page from reloading. It also calls the main function <code>addPosts()</code> by passing the data entered into the form as a parameter.</p>
<h3 id="heading-how-to-perform-a-delete-request-in-react">How to Perform a DELETE Request in React</h3>
<p>As the name implies, you use this to delete specific data from your endpoint/API as well as your UI – DELETE can handle both.</p>
<p>For this, we will use the DELETE method in conjunction with the client variable where we initialized Axios. This is how the request will look:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   <span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">const</span> deletePost = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
      client.delete(<span class="hljs-string">`<span class="hljs-subst">${id}</span>`</span>);
      setPosts(
         posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> post.id !== id;
         })
      );
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Basically, there is a <code>onClick"=() =&gt;"deletePost"("post."id)</code> method on the delete button that triggers the <code>deletePost()</code> method. We passed it the <code>ID</code> of the particular post we are attempting to delete so we can identify the post.</p>
<p>We delete it from the UI after we delete it from the endpoint/API by using the filter method to return an array that does not contain that element.</p>
<h2 id="heading-how-to-make-requests-in-react-with-asyncawait">How to Make Requests in React with Async/Await</h2>
<p>So far, we've seen how to make Axios requests with the promise syntax. Now, let's see how we can use async/await to write less code and avoid the <code>.then</code> chaining, which is much more difficult to understand.</p>
<p>To use async/await, first call <code>async</code> in the function. Then add the <code>await</code> syntax in front of the function when making a request and expecting a response to wait until the promise settles with the result.</p>
<p>When we use async/await, all of our Axios requests will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

    <span class="hljs-comment">// GET with Axios</span>
   useEffect(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
         <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'?_limit=10'</span>);
         setPosts(response.data);
      };
      fetchPost();
   }, []);

   <span class="hljs-comment">// DELETE with Axios</span>
   <span class="hljs-keyword">const</span> deletePost = <span class="hljs-keyword">async</span> (id) =&gt; {
      <span class="hljs-keyword">await</span> client.delete(<span class="hljs-string">`<span class="hljs-subst">${id}</span>`</span>);
      setPosts(
         posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> post.id !== id;
         })
      );
   };

   <span class="hljs-comment">// handle form submission</span>
   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      addPosts(title, body);
   };

   <span class="hljs-comment">// POST with Axios</span>
   <span class="hljs-keyword">const</span> addPosts = <span class="hljs-keyword">async</span> (title, body) =&gt; {
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">''</span>, {
         <span class="hljs-attr">title</span>: title,
         <span class="hljs-attr">body</span>: body,
      });
      setPosts([response.data, ...posts]);
      setTitle(<span class="hljs-string">''</span>);
      setBody(<span class="hljs-string">''</span>);
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};
</code></pre>
<h2 id="heading-how-to-handle-errors-in-axios">How to Handle Errors in Axios</h2>
<p>When consuming data from an API, it is always recommended that we handle errors to help show the type of error we get. These errors may occur as a result of us passing incorrect data, making a request to the incorrect API, or experiencing a network error.</p>
<p>We can handle errors in Axios by using the <code>.then()</code> and <code>.catch()</code> methods, or by using the <code>try...catch</code> block for async/await Axios requests.</p>
<h3 id="heading-how-to-handle-errors-in-axios-with-the-catch-method">How to Handle Errors in Axios with the <code>.catch</code> Method</h3>
<p>You can implement this by attaching a <code>.catch()</code> method to the <code>.then()</code> method to handle errors. Suppose the <code>.then()</code> method fails:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  client
     .get(<span class="hljs-string">'?_limit=10'</span>)
     .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
        setPosts(response.data);
     })
     .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(error);
     });
}, []);
</code></pre>
<h3 id="heading-how-to-handle-errors-in-axios-with-the-trycatch-block">How to Handle Errors in Axios with the try…catch Block</h3>
<p>For the async/await scenario, the <code>try...catch</code> block will look like this:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
     <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'?_limit=10'</span>);
        setPosts(response.data);
     } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
     }
  };
  fetchPost();
}, []);
</code></pre>
<p>You can read more about handling errors with Axios <a target="_blank" href="https://stackabuse.com/handling-errors-with-axios/">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to use Axios, one of the most powerful HTTP client libraries, to perform the three basic API requests.</p>
<p>You can see the full implementation of how I built the <a target="_blank" href="https://github.com/olawanlejoel/posts-jsonplaceholder-demo">post's application using React and Axios in this repository</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Use Axios With React: The Definitive Guide (2021) ]]>
                </title>
                <description>
                    <![CDATA[ In this guide, you will see exactly how to use Axios.js with React using tons of real-world examples featuring React hooks.  You'll see why you should use Axios as a data fetching library, how to set it up with React, and perform every type of HTTP r... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-axios-with-react/</link>
                <guid isPermaLink="false">66d0378f871ae63f179f6baf</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react hooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Reed ]]>
                </dc:creator>
                <pubDate>Tue, 13 Jul 2021 07:36:28 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/how-to-use-axios-with-react.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this guide, you will see exactly how to use Axios.js with React using tons of real-world examples featuring React hooks. </p>
<p>You'll see why you should use Axios as a data fetching library, how to set it up with React, and perform every type of HTTP request with it.</p>
<p>Then we'll touch on more advanced features like creating an Axios instance for reusability, using async-await with Axios for simplicity, and how to use Axios as a custom hook.</p>
<p>Let's dive right in!</p>
<h3 id="heading-want-your-own-copy"><strong>Want Your Own Copy?‬ 📄</strong></h3>
<p><strong><a target="_blank" href="https://reedbarger.com/resources/react-axios-2021">Click here to download the cheatsheet in PDF format</a></strong> (it takes 5 seconds).</p>
<p>It includes all of the essential information here as a convenient PDF guide.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-axios">What is Axios?</a></li>
<li><a class="post-section-overview" href="#heading-why-use-axios-in-react">Why Use Axios in React?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-axios-with-react">How to Set Up Axios with React</a></li>
<li><a class="post-section-overview" href="#heading-how-to-make-a-get-request">How to Make a GET Request (Retrieve Data)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-make-a-post-request">How to Make a POST Request (Create Data)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-make-a-put-request">How to Make a PUT Request (Update Data)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-make-a-delete-request">How to Make a DELETE Request (Delete Data)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-errors-with-axios">How to Handle Errors with Axios</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-an-axios-instance">How to Create an Axios Instance</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-async-await-syntax-with-axios">How to Use the Async-Await Syntax with Axios</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-custom-useaxios-hook">How to Create a Custom <code>useAxios</code> Hook</a></li>
</ul>
<h2 id="heading-what-is-axios">What is Axios?</h2>
<p>Axios is an HTTP client library that allows you to make requests to a given endpoint:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/Screen-Shot-2021-07-12-at-1.14.41-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This could be an external API or your own backend Node.js server, for example.</p>
<p>By making a request, you expect your API to perform an operation according to the request you made.</p>
<p>For example, if you make a GET request, you expect to get back data to display in your application.</p>
<h2 id="heading-why-use-axios-in-react">Why Use Axios in React</h2>
<p>There are a number of different libraries you can use to make these requests, so why choose Axios? </p>
<p>Here are <strong>five reasons</strong> why you should use Axios as your client to make HTTP requests: </p>
<ol>
<li>It has good defaults to work with JSON data. Unlike alternatives such as the Fetch API, you often don't need to set your headers. Or perform tedious tasks like converting your request body to a JSON string.</li>
<li>Axios has function names that match any HTTP methods. To perform a GET request, you use the <code>.get()</code> method.</li>
<li>Axios does more with less code. Unlike the Fetch API, you only need one <code>.then()</code> callback to access your requested JSON data.</li>
<li>Axios has better error handling. Axios throws 400 and 500 range errors for you. Unlike the Fetch API, where you have to check the status code and throw the error yourself. </li>
<li>Axios can be used on the server as well as the client. If you are writing a Node.js application, be aware that Axios can also be used in an environment separate from the browser. </li>
</ol>
<h2 id="heading-how-to-set-up-axios-with-react">How to Set Up Axios with React</h2>
<p>Using Axios with React is a very simple process. You need three things:</p>
<ol>
<li>An existing React project</li>
<li>To install Axios with npm/yarn</li>
<li>An API endpoint for making requests</li>
</ol>
<p>The quickest way to create a new React application is by going to <a target="_blank" href="https://react.new">react.new</a>.</p>
<p>If you have an existing React project, you just need to install Axios with npm (or any other package manager):</p>
<pre><code class="lang-bash">npm install axios
</code></pre>
<p>In this guide, you'll use the JSON Placeholder API to get and change post data.</p>
<p>Here is a list of all the different routes you can make requests to, along with the appropriate HTTP method for each:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/Screen-Shot-2021-07-10-at-12.21.28-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here is a quick example of all of the operations you'll be performing with Axios and your API endpoint — retrieving, creating, updating, and deleting posts:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/axios-react.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-make-a-get-request">How to Make a GET Request</h2>
<p>To fetch data or retrieve it, make a GET request.</p>
<p>First, you're going to make a request for individual posts. If you look at the endpoint, you are getting the first post from the <code>/posts</code> endpoint:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    axios.get(baseURL).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPost(response.data);
    });
  }, []);

  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>To perform this request when the component mounts, you use the <code>useEffect</code> hook. This involves importing Axios, using the <code>.get()</code> method to make a GET request to your endpoint, and using a <code>.then()</code> callback to get back all of the response data.</p>
<p>The response is returned as an object. The data (which is in this case a post with <code>id</code>, <code>title</code>, and <code>body</code> properties) is put in a piece of state called <code>post</code> which is displayed in the component. </p>
<p>Note that you can always find the requested data from the <code>.data</code> property in the response.</p>
<h2 id="heading-how-to-make-a-post-request">How to Make a POST Request</h2>
<p>To create new data, make a POST request. </p>
<p>According to the API, this needs to be performed on the <code>/posts</code> endpoint. If you look at the code below, you'll see that there's a button to create a post:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    axios.get(<span class="hljs-string">`<span class="hljs-subst">${baseURL}</span>/1`</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPost(response.data);
    });
  }, []);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createPost</span>(<span class="hljs-params"></span>) </span>{
    axios
      .post(baseURL, {
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Hello World!"</span>,
        <span class="hljs-attr">body</span>: <span class="hljs-string">"This is a new post."</span>
      })
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
        setPost(response.data);
      });
  }

  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-string">"No post!"</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{createPost}</span>&gt;</span>Create Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>When you click on the button, it calls the <code>createPost</code> function.</p>
<p>To make that POST request with Axios, you use the <code>.post()</code> method. As the second argument, you include an object property that specifies what you want the new post to be.</p>
<p>Once again, use a <code>.then()</code> callback to get back the response data and replace the first post you got with the new post you requested.</p>
<p>This is very similar to the <code>.get()</code> method, but the new resource you want to create is provided as the second argument after the API endpoint.</p>
<h2 id="heading-how-to-make-a-put-request">How to Make a PUT Request</h2>
<p>To update a given resource, make a PUT request.</p>
<p>In this case, you'll update the first post.</p>
<p>To do so, you'll once again create a button. But this time, the button will call a function to update a post:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    axios.get(<span class="hljs-string">`<span class="hljs-subst">${baseURL}</span>/1`</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPost(response.data);
    });
  }, []);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updatePost</span>(<span class="hljs-params"></span>) </span>{
    axios
      .put(<span class="hljs-string">`<span class="hljs-subst">${baseURL}</span>/1`</span>, {
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Hello World!"</span>,
        <span class="hljs-attr">body</span>: <span class="hljs-string">"This is an updated post."</span>
      })
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
        setPost(response.data);
      });
  }

  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-string">"No post!"</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{updatePost}</span>&gt;</span>Update Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code above, you use the PUT method from Axios. And like with the POST method, you include the properties that you want to be in the updated resource.</p>
<p>Again, using the <code>.then()</code> callback, you update the JSX with the data that is returned.</p>
<h2 id="heading-how-to-make-a-delete-request">How to Make a DELETE Request</h2>
<p>Finally, to delete a resource, use the DELETE method.</p>
<p>As an example, we'll delete the first post.</p>
<p>Note that you do not need a second argument whatsoever to perform this request:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    axios.get(<span class="hljs-string">`<span class="hljs-subst">${baseURL}</span>/1`</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPost(response.data);
    });
  }, []);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deletePost</span>(<span class="hljs-params"></span>) </span>{
    axios
      .delete(<span class="hljs-string">`<span class="hljs-subst">${baseURL}</span>/1`</span>)
      .then(<span class="hljs-function">() =&gt;</span> {
        alert(<span class="hljs-string">"Post deleted!"</span>);
        setPost(<span class="hljs-literal">null</span>)
      });
  }

  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-string">"No post!"</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{deletePost}</span>&gt;</span>Delete Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In most cases, you do not need the data that's returned from the <code>.delete()</code> method.</p>
<p>But in the code above, the <code>.then()</code> callback is still used to ensure that your request is successfully resolved.</p>
<p>In the code above, after a post is deleted, the user is alerted that it was deleted successfully. Then, the post data is cleared out of the state by setting it to its initial value of <code>null</code>.</p>
<p>Also, once a post is deleted, the text "No post" is shown immediately after the alert message.</p>
<h2 id="heading-how-to-handle-errors-with-axios">How to Handle Errors with Axios</h2>
<p>What about handling errors with Axios? </p>
<p>What if there's an error while making a request? For example, you might pass along the wrong data, make a request to the wrong endpoint, or have a network error.</p>
<p>To simulate an error, you'll send a request to an API endpoint that doesn't exist: <code>/posts/asdf</code>.</p>
<p>This request will return a <code>404</code> status code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [error, setError] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// invalid url will trigger an 404 error</span>
    axios.get(<span class="hljs-string">`<span class="hljs-subst">${baseURL}</span>/asdf`</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPost(response.data);
    }).catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
      setError(error);
    });
  }, []);

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="hljs-string">`Error: <span class="hljs-subst">${error.message}</span>`</span>;
  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-string">"No post!"</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In this case, instead of executing the <code>.then()</code> callback, Axios will throw an error and run the <code>.catch()</code> callback function.</p>
<p>In this function, we are taking the error data and putting it in state to alert our user about the error. So if we have an error, we will display that error message.</p>
<p>In this function, the error data is put in state and used to alert users about the error. So if there's an error, an error message is displayed.</p>
<p>When you run this code code, you'll see the text, "Error: Request failed with status code 404".</p>
<h2 id="heading-how-to-create-an-axios-instance">How to Create an Axios Instance</h2>
<p>If you look at the previous examples, you'll see that there's a <code>baseURL</code> that you use as part of the endpoint for Axios to perform these requests.</p>
<p>However, it gets a bit tedious to keep writing that <code>baseURL</code> for every single request. Couldn't you just have Axios remember what <code>baseURL</code> you're using, since it always involves a similar endpoint? </p>
<p>In fact, you can. If you create an instance with the <code>.create()</code> method, Axios will remember that <code>baseURL</code>, plus other values you might want to specify for every request, including headers: </p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> client = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span> 
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    client.get(<span class="hljs-string">"/1"</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
      setPost(response.data);
    });
  }, []);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deletePost</span>(<span class="hljs-params"></span>) </span>{
    client
      .delete(<span class="hljs-string">"/1"</span>)
      .then(<span class="hljs-function">() =&gt;</span> {
        alert(<span class="hljs-string">"Post deleted!"</span>);
        setPost(<span class="hljs-literal">null</span>)
      });
  }

  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-string">"No post!"</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{deletePost}</span>&gt;</span>Delete Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>The one property in the config object above is <code>baseURL</code>, to which you pass the endpoint.</p>
<p>The <code>.create()</code> function returns a newly created instance, which in this case is called <code>client</code>.</p>
<p>Then in the future, you can use all the same methods as you did before, but you don't have to include the <code>baseURL</code> as the first argument anymore. You just have to reference the specific route you want, for example, <code>/</code>, <code>/1</code>, and so on.</p>
<h2 id="heading-how-to-use-the-async-await-syntax-with-axios">How to Use the Async-Await Syntax with Axios</h2>
<p>A big benefit to using promises in JavaScript (including React applications) is the async-await syntax.</p>
<p>Async-await allows you to write much cleaner code without <code>then</code> and <code>catch</code> callback functions. Plus, code with async-await looks a lot like synchronous code, and is easier to understand.</p>
<p>But how do you use the async-await syntax with Axios?</p>
<p>In the example below, posts are fetched and there's still a button to delete that post:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> client = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span> 
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [post, setPost] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPost</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">"/1"</span>);
      setPost(response.data);
    }
    getPost();
  }, []);

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deletePost</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">await</span> client.delete(<span class="hljs-string">"/1"</span>);
    alert(<span class="hljs-string">"Post deleted!"</span>);
    setPost(<span class="hljs-literal">null</span>);
  }

  <span class="hljs-keyword">if</span> (!post) <span class="hljs-keyword">return</span> <span class="hljs-string">"No post!"</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{deletePost}</span>&gt;</span>Delete Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>However in <code>useEffect</code>, there's an <code>async</code> function called <code>getPost</code>.</p>
<p>Making it <code>async</code> allows you to use the <code>await</code> keword to resolve the GET request and set that data in state on the next line without the <code>.then()</code> callback. </p>
<p>Note that the <code>getPost</code> function is called immediately after being created.</p>
<p>Additionally, the <code>deletePost</code> function is now <code>async</code>, which is a requirement to use the <code>await</code> keyword which resolves the promise it returns (every Axios method returns a promise to resolve).</p>
<p>After using the <code>await</code> keyword with the DELETE request, the user is alerted that the post was deleted, and the post is set to <code>null</code>.</p>
<p>As you can see, async-await cleans up the code a great deal, and you can use it with Axios very easily.</p>
<h2 id="heading-how-to-create-a-custom-useaxios-hook">How to Create a Custom <code>useAxios</code> Hook</h2>
<p>Async-await is a great way to simplify your code, but you can take this a step further.</p>
<p>Instead of using <code>useEffect</code> to fetch data when the component mounts, you could create your own custom hook with Axios to perform the same operation as a reusable function.</p>
<p>While you can make this custom hook yourself, there's a very good library that gives you a custom <code>useAxios</code> hook called use-axios-client.</p>
<p>First, install the package:</p>
<pre><code>npm install use-axios-client
</code></pre><p>To use the hook itself, import <code>useAxios</code> from use-axios-client at the top of the component. </p>
<p>Because you no longer need <code>useEffect</code>, you can remove the React import:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useAxios } <span class="hljs-keyword">from</span> <span class="hljs-string">"use-axios-client"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, error, loading } = useAxios({
    <span class="hljs-attr">url</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/1"</span>
  });

  <span class="hljs-keyword">if</span> (loading || !data) <span class="hljs-keyword">return</span> <span class="hljs-string">"Loading..."</span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="hljs-string">"Error!"</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{data.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  ) 
}
</code></pre>
<p>Now you can call <code>useAxios</code> at the top of the app component, pass in the URL you want to make a request to, and the hook returns an object with all the values you need to handle the different states: <code>loading</code>, <code>error</code> and the resolved <code>data</code>.</p>
<p>In the process of performing this request, the value <code>loading</code> will be true. If there's an error, you'll want to display that error state. Otherwise, if you have the returned data, you can display it in the UI.</p>
<p>The benefit of custom hooks like this is that it really cuts down on code and simplifies it overall. </p>
<p>If you're looking for even simpler data fetching with Axios, try out a custom <code>useAxios</code> hook like this one.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<p>Congratulations! You now know how to use one of the most powerful HTTP client libraries to power your React applications. </p>
<p>I hope you got a lot out of this guide.</p>
<p><a target="_blank" href="https://reedbarger.com/resources/react-axios-2021">Remember that you can download this guide as a PDF cheatsheet to keep for future reference.</a></p>
<h2 id="heading-become-a-professional-react-developer">Become a Professional React Developer</h2>
<p>React is hard. You shouldn't have to figure it out yourself.</p>
<p>I've put everything I know about React into a single course, to help you reach your goals in record time:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><strong>Introducing: The React Bootcamp</strong></a></p>
<p><strong>It’s the one course I wish I had when I started learning React.</strong></p>
<p>Click below to try the React Bootcamp for yourself:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/reactbootcamp/react-bootcamp-cta-alt.png" alt="Click to join the React Bootcamp" width="600" height="400" loading="lazy"></a>
<em>Click to get started</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build and Deploy a Portfolio with Vue.js Axios, the GitHub REST API, and Netlify ]]>
                </title>
                <description>
                    <![CDATA[ By Fabio Pacific In this free book, we will build two simple projects and deploy them on Netlify. We will use Vue.js as our front-end framework, and use different technologies to build our projects.  If you follow this tutorial to the end, you will b... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-portfolio-with-vuejs/</link>
                <guid isPermaLink="false">66d45edcb3016bf139028d31</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ portfolio ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 12 May 2021 20:53:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/05/VUE.JS-_-Article-Cover.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Fabio Pacific</p>
<p>In this free book, we will build two simple projects and deploy them on Netlify. We will use Vue.js as our front-end framework, and use different technologies to build our projects. </p>
<p>If you follow this tutorial to the end, you will build a simplified version of Twitter and a single page application for a portfolio using the GitHub API.</p>
<h2 id="heading-what-you-need-to-know-to-follow-this-tutorial">What you need to know to follow this tutorial</h2>
<p>To follow along, you will need at least some basic knowledge of HTML, CSS, and JavaScript. </p>
<p>Knowledge of Vue.js isn't required, as you will learn the basics first and then we'll move into building the projects together.</p>
<p>At the end of each section, you'll find that information in video form via a YouTube link/embed. That way you can watch the videos to cement your knowledge of what you just read.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-introduction">Introduction</a></li>
<li><a class="post-section-overview" href="#heading-how-to-install-vue">How to Install Vue</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-vue-instance">How to Create a Vue Instance</a></li>
<li><a class="post-section-overview" href="#heading-how-to-work-with-templates-in-vue">How to Work with Templates in Vue</a></li>
<li><a class="post-section-overview" href="#heading-vue-directives">Vue Directives</a></li>
<li><a class="post-section-overview" href="#heading-methods-in-vue">Methods</a></li>
<li><a class="post-section-overview" href="#heading-conditionals-in-vue-v-ifv-else-ifv-elsev-show">Conditionals</a></li>
<li><a class="post-section-overview" href="#heading-loops-in-vue">Loops</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-user-input-with-event-handling-v-on-in-vue">How to handle user inputs with events Handling</a></li>
<li><a class="post-section-overview" href="#heading-two-way-model-binding-v-model-in-vue">Two way model binding (v-model)</a></li>
<li><a class="post-section-overview" href="#heading-computed-properties-and-methods">Computed Properties and methods</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-simple-twitter-clone"><strong>Project</strong>: Simple Twitter Clone</a></li>
<li><a class="post-section-overview" href="#heading-vue-component-basics">Component basics</a></li>
<li><a class="post-section-overview" href="#heading-how-to-update-your-simpletwitter-project-with-components">Project Update: Simple Twitter clone with components</a></li>
<li><a class="post-section-overview" href="#heading-how-to-perform-api-calls-with-axios">Axios and RestAPI</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-routing-with-vuerouter">Routing with VueRouter</a></li>
<li><a class="post-section-overview" href="#heading-final-project-how-to-build-a-portfolio-with-vuejs-vuerouter-axios-github-api-and-deploy-to-netlify"><strong>Final Project</strong>: build a Portfolio with VueJS, VueRouter, Axios, GitHub API</a></li>
<li><a class="post-section-overview" href="#heading-continuos-deployment-with-bitbucket-and-netlify"><strong>Deploy</strong> Continuous deployment with BitBucket and Netlify</a></li>
</ul>
<h2 id="heading-introduction">Introduction</h2>
<p>VueJS is a JavaScript framework that has become really popular in recent years. </p>
<p>In this guide, we will start by looking at the fundamentals first, with a quick look at two libraries: VueRouter and Axios. We will use them to build a cool portfolio project at the end.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/CzgP6GamIMc" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Click to view the video on <a target="_blank" href="https://youtu.be/CzgP6GamIMc">YouTube</a>.</p>
<h2 id="heading-how-to-install-vue">How to Install Vue</h2>
<p>You can use Vue in your projects by installing it using a package manager like NPM or by using its CDN. If you've never used Vuejs before, I suggest that you use the CDN, as it will be easier if you want to code along with me. </p>
<p>Click to view the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/1-installation/">Repository</a></p>
<p>Click to view the <a target="_blank" href="https://youtu.be/enz0Vi3NuDA">YouTube-Video</a> or find it at the end of this section to reinforce what you've learned.</p>
<h3 id="heading-the-vue-cdn">The Vue CDN</h3>
<p>For the CDN, we only need to include the script tag below inside our HTML file:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Development version for prototyping and learning --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Alternatively, you can use a production-ready script that uses a specific stable release, like this:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Production version --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue@2.6.12"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>In production, Vue suggests using the optimized version to replace vue.js with vue.min.js.</p>
<p>There is also an ES Modules-compatible build:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.esm.browser.js'</span>
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-install-vue-via-npm">How to Install Vue via NPM</h3>
<p>If you plan to build large scale applications, I recommend installing via NPM like this:</p>
<pre><code class="lang-bash">npm install vue
</code></pre>
<p>As I said above, we will use the Vue CDN so that anyone can follow this guide. So our final HTML file will look something like this: </p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>VueJS Tutorial<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- vue development version, includes helpful console warnings --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>



    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Let's break this code down. First, we've add a basic markup for an HTML file. Then we've included the script tag for the VueJs framework. </p>
<p>In the end, before closing the body tag, we've added our main.js script where we placed all the JavaScript code for our application. </p>
<p>Let's now move to the next step and add our first Vue instance inside the main.js file.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/enz0Vi3NuDA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-create-a-vue-instance">How to Create a Vue Instance</h2>
<p>Once you've installed Vue or included it via its CDN, you can create a Vue instance. You can do that using the <code>new Vue()</code> function. This function accepts an object of options.</p>
<p>If you read the documentation, you will see that the vue instance is often stored inside a variable called <code>vm</code>, but you can call it anything you like. I'll call it <code>app</code> during this guide.</p>
<p>So now, inside the main.js file you need to create a variable and store in it the Vue instance like so:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">// all options goes here</span>
})
</code></pre>
<p>The object you pass to the Vue instance is called the options object.
Inside the options object, you can add all the options described in the Vue API reference pages to build our application. </p>
<p>The options object has properties divided into multiple sections: </p>
<ul>
<li>Data </li>
<li>DOM </li>
<li>Life Cycle Hooks </li>
<li>Assets</li>
<li>Composition </li>
<li>Misc categories </li>
</ul>
<p>The first property that you need to build you Vue application is used to connect Vue with a root DOM element. Then you will need some data options to work with.</p>
<p>Let's start by connecting the Vue instance with a root DOM element.</p>
<p>You can click to view the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/2-create-vue-instance/">Repository</a> here.</p>
<p>And you can click to view the <a target="_blank" href="https://youtu.be/gBJaL7Jqh4w">YouTube-Video</a> or find it at the end of this section so you can review what you've learned.</p>
<h3 id="heading-optionsdom-how-to-select-the-root-dom-element">Options/DOM: How to select the root DOM element</h3>
<p>The Options/DOM API gives you an <code>el</code> property that you can use to select an existing DOM element that Vue will use to mount your application instance. </p>
<p>The <code>el</code> property accepts a string that contains a CSS selector for the element or directly a DOM element.</p>
<p>NOTE: Vue discourages using the body or HTML tags and suggests using a different element as a mounting point.</p>
<p>Let's do it. Inside the body of the index.html file, you need to put the following code:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now you have a root element that you can use to connect the Vue instance.
Back inside the main.js file, let's select this element inside the options object. </p>
<p>You can now use the <code>el</code> property to select the element you created with an id of <code>app</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">// all options go here</span>
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
})
</code></pre>
<p>You now have an element to work with. You can move on to the next step and add to the options object the data object.</p>
<p>You can read more about it in the documentation here:[https://vuejs.org/v2/api/#Options-DOM]</p>
<h3 id="heading-optionsdata-how-to-add-the-data-object-or-function-when-used-in-a-component">Options/Data: How to add the data object (or function when used in a component)</h3>
<p>When a new instance is created, it adds all properties found in its data object to the Vue reactivity system. And when a value in the data object changes, the view will reflect these changes. This is at the base of the VueJS reactivity system. </p>
<p>To explain it, let's see a practical example.</p>
<h4 id="heading-create-a-data-object">Create a data object</h4>
<p>Inside the main.js file you can create a data property that has an object as its value, like so:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">// all options go here</span>
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {}
})
</code></pre>
<p>The data object can be defined directly inside the Vue instance like in the code above, or outside the instance like in the code below. </p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> dataObject = {}
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">// all options go here</span>
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: dataObject
})
</code></pre>
<p>You can pick the one you like.</p>
<h4 id="heading-add-properties-to-the-data-object">Add properties to the Data Object</h4>
<p>Since VueJs is a JavaScript framework, it's helpful to remember that what you know about JavaScript is still valuable here. </p>
<p>Vue is just a JavaScript object that has a number of methods and properties that you can use to simplify and speed up your workflow.</p>
<p>Let's add some properties to the data object to see how it works.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Create a data object</span>
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>:<span class="hljs-string">"#app"</span>,
    <span class="hljs-comment">// create a vue instance, add the data property and the dataObject created</span>
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">alert</span>: <span class="hljs-string">"This is an alert message! "</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"portfolio"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"VueJS"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"grocery shop"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"blog"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"automation script"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"Python"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"eCommerce"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
        ];
    }
})
</code></pre>
<p>With the code above, you simply add two properties to the data object: an <code>alert</code> property and a  <code>projects</code> property. </p>
<p>The alert property just a string while the projects property is an array of objects. </p>
<p>Now that you have some data to work with, let's see how you can access and modify their values.</p>
<h4 id="heading-manipulate-properties-in-the-data-object">Manipulate properties in the data object</h4>
<p>You can access and manipulate the properties of a data object using the variable that contains the Vue instance <code>app</code>. Then you can reference the properties using dot notation, like <code>app.alert</code>. </p>
<p>In the browser, if you open the console you can see that when you write <code>app</code> you get the Vue instance object. So, like any other object with dot notation, you get its properties and methods.</p>
<p>Let's try this out inside the console:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Access the alert property in the data object</span>
app.alert <span class="hljs-comment">// This is an alert message!</span>
<span class="hljs-comment">// update a data property value</span>
app.alert = <span class="hljs-string">"This is a new alert message!"</span> 
app.projects
</code></pre>
<p>The code above does three simple things:</p>
<ul>
<li>the first line accesses the <code>alert</code> property and prints its content "this is an alert message"</li>
<li>the second line assigns a new value to the <code>alert</code> property with the equals operator</li>
<li>finally, the third line returns the value of the projects array. </li>
</ul>
<p>You can also access the entire data object using the shortcuts $data or _data</p>
<p>Back in the console:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Access the entrie data object</span>
app.$data <span class="hljs-comment">// {__ob__: Observer} option 1</span>
app._data <span class="hljs-comment">// {__ob__: Observer} option 2</span>
</code></pre>
<p>You can read more about this in the documentation here: [https://vuejs.org/v2/api/#Options-Data]</p>
<h3 id="heading-options-data-methods">Options Data Methods</h3>
<p>The Vue instance gives you access to a number of properties and methods.
You can access default methods and properties using the <code>$</code> sign. It is used to differentiate Vue defined methods from those defined by the user.</p>
<p>There are a number of instance methods and properties predefined and split into four different categories:</p>
<ul>
<li>Instance Properties</li>
<li>Instance Methods / Data</li>
<li>Instance Methods / Events</li>
<li>Instance Methods/life cycle hooks</li>
</ul>
<p>For instance, with the following code, you can get the <code>data</code> and <code>options</code> objects or access the <code>watch</code> or the <code>on</code> methods. </p>
<pre><code class="lang-js">app.$data <span class="hljs-comment">// returns the data object</span>
app.$options <span class="hljs-comment">// returns the options object</span>
app.$watch() <span class="hljs-comment">// function that watched for changes on the vue instance</span>
app.$on() <span class="hljs-comment">// listen for a custom event on the vue instance</span>
</code></pre>
<p>I won't dive deeper into this since it's out of the scope of this guide. But if you are interested and want to learn more, here is the <a target="_blank" href="https://vuejs.org/v2/api/#Instance-Properties">documentation</a>.</p>
<h3 id="heading-lifecycle-hooks">Lifecycle Hooks</h3>
<p>Vue gives you access to a series of functions called lifecycle hooks. They allow you to run code at specific stages of the Vue initialization steps.</p>
<p>Inside all lifecycle hooks you have access to their <code>this</code> variable that points to the Vue instance. </p>
<p>You will see how this works in more detail in future sections. But for now this is a short summary of the available hooks and what they let you do:</p>
<ul>
<li>beforeCreate (you can run code before the Vue instance is created)</li>
<li>created (you can run code after the Vue instance is created )</li>
<li>beforeMount (you can run code before your element is mounted to the DOM)</li>
<li>mounted (you can run code when the element is mounted to the DOM)</li>
<li>beforeUpdate (you can run code before values are updated in the DOM)</li>
<li>updated (you can run code after values in the DOM have been updated)</li>
<li>beforeDestroy (you can run code before an instance is destroyed)</li>
<li>destroyed (you can run code when an instance is destroyed)</li>
</ul>
<p>During the course, we will often use the mounted hook. If you are curious to learn more about this topic, I suggest you look at the diagram in the documentation first. Find the lifecycle Hooks <a target="_blank" href="https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram">diagram</a> here.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/gBJaL7Jqh4w" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-work-with-templates-in-vue">How to Work with Templates in Vue</h2>
<p>VueJS uses mustache syntax <code>{{ }}</code> to render data from the Vue instance inside the HTML element. </p>
<p>Using this syntax you can grab properties and methods defined in the Vue instance. The property is then parsed and rendered to the page.</p>
<p>You can click to view the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/3-work-with-templates/">Repository here</a>.</p>
<p>And you can click to view the <a target="_blank" href="https://youtu.be/pDj3SQ8TNzs">YouTube-Video here</a> here, or find it at the end of this section to review what you've just learned.</p>
<h3 id="heading-text-data-binding">Text Data binding</h3>
<p>This is called text data binding. Let's see an example of how you can bind data between the Vue instance and your template file. </p>
<pre><code class="lang-html">
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The code above has an <code>h1</code> tag inside the root element with an id of <code>app</code> we defined in the previous chapter. </p>
<p>Inside the <code>h1</code> tag you use the double curly brackets syntax to render onto the page the value of a property in the data object called that you called <code>title</code>. </p>
<p>You don't have a <code>title</code> property yet inside your data object, so let's add it.</p>
<p>Inside the main.js file</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-string">"John Doe portfolio"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"portfolio"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"VueJS"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"grocery shop"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"blog"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"automation script"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"Python"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"eCommerce"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
        ]
    }
})
</code></pre>
<p>Now, with the code above you can render the content of the property <code>title</code> inside the <code>h1</code> tag in your template. The final result will be something like this: </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>John Doe portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<p>However, with this method, you can only pass a string. If you want to use HTML tags inside the string these will not be parsed but instead will be shown as simple strings.</p>
<p>For instance if you assign the following string to the <code>title</code> property</p>
<pre><code class="lang-js">    title: <span class="hljs-string">"John Doe &lt;span class='badge'&gt;Portfolio&lt;/span&gt;"</span>
</code></pre>
<p>And then try to render it inside our HTML like so:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>{{title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<p>The property <code>title</code> will be rendered as a plain string including the HTML tags 
ie. <code>John Doe &lt;span class='badge'&gt;Portfolio&lt;/span&gt;</code></p>
<p>Of course you can parse HTML too.</p>
<h3 id="heading-how-to-parse-raw-html">How to parse raw HTML</h3>
<p>To render a raw HTML element we need to introduce another important Vue concept called directives. </p>
<p>In this case, you will use the v-html directive inside your HTML tag as an attribute and pass to it the property title. </p>
<p>When you're using Vue directives, the text inside the quotes is considered a JavaScript expression. This means that it's computed and its result is rendered.  </p>
<p>Let's create a separate property for the title with HTML tags inside so that you can see how both render onto the page. </p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-string">"John Doe Portfolio"</span>, 
        <span class="hljs-attr">titleHTLM</span> : <span class="hljs-string">"John Doe &lt;span class='badge'&gt;Portfolio&lt;/span&gt;"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"portfolio"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"VueJS"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"grocery shop"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"blog"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"automation script"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"Python"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"eCommerce"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
        ]
    }
})
</code></pre>
<p>Now inside your HTML file, you will use this <code>{{}}</code> syntax to render the property <code>title</code>. But on the tag where you want to render raw HTML, with the <code>titleHTML</code> property, you use the v-html directive instead.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-html</span>=<span class="hljs-string">"titleHTML"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Both elements will now render correctly including the second property that has HTML tags inside.</p>
<p>NOTE: Rendering HTML can expose XSS vulnerabilities. Never use this approach on user-provided content.</p>
<p>Now that you know how to render data onto the page, let's dig deeper into directives. </p>
<p>If you want to read more, visit the documentation 
<a target="_blank" href="https://vuejs.org/v2/guide/syntax.html#Using-JavaScript-Expressions">here</a>.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/pDj3SQ8TNzs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-vue-directives">Vue Directives</h2>
<p>Inside your HTML files, you can use directives to interact with HTML attributes. A directive applies effects to the DOM when its expression changes. </p>
<p>You can click to view the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/4-Directives/">Repository here</a></p>
<p>And you can click to view the <a target="_blank" href="https://youtu.be/LICvNmhsTEs">YouTube-Video here</a>, or you can find it at the end of this section to review what you've learned.</p>
<h3 id="heading-the-v-bind-directive-on-html-attributes">The v-bind directive on HTML attributes</h3>
<p>So far, you have used the <code>{{}}</code> syntax to render something between HTML opening and closing tags. But inside an HTML tag you cannot use the {{ }} syntax. </p>
<p>So how do you connect an HTML attribute to the Vue instance? You use the v-bind directive instead which lets you access data object properties as you have done before. </p>
<p>The v-bind directive is one of the directives that take arguments which are specified after the colon. In our case here, what's specified after the colon is the HTML attribute name like id, class, href, src and so on. </p>
<p>If you need to dynamically assign an attribute like href or even a class, you can bind it with the Vue instance using the v-bind directive. It will then be able to get what's in the options object, like properties in the data object.</p>
<p>Let's see v-bind in action and start connecting the <code>id</code> and <code>class</code> attributes so you can assign them values dynamically with Vue.</p>
<p>Inside our index.html file:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-bind:class</span>=<span class="hljs-string">"dynamicClass"</span> <span class="hljs-attr">v-bind:id</span>=<span class="hljs-string">"dynamicId"</span>&gt;</span>Dinamically assign a class and an id to the div<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Let's break the code above and see what it's doing. </p>
<p>First, you have a <code>div</code> tag inside the root element. Then you use the v-bind directive on the class and the id attributes. </p>
<p>Inside the quotes, you specify two properties that later you'll define inside the data object of your Vue instance.</p>
<p>Remember that when using Vue directives the content between quotes is treated as a JavaScript expression.</p>
<p>Let's define these two properties inside the Vue instance.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-string">"John Doe Portfolio"</span>, 
        <span class="hljs-attr">titleHTLM</span> : <span class="hljs-string">"John Doe &lt;span class='badge'&gt;Portfolio&lt;/span&gt;"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"portfolio"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"VueJS"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"grocery shop"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"blog"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"automation script"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"Python"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"eCommerce"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
        ],
        <span class="hljs-attr">dynamicId</span> : <span class="hljs-string">"projects_section"</span>,
        <span class="hljs-attr">dynamicClass</span> : <span class="hljs-string">"projects"</span>
    }
})
</code></pre>
<p>So you have defined <code>dinamicId: "projects_section"</code> and <code>dynmicClass: "projects"</code> properties and assigned them two values.</p>
<p>Thanks to the data binding on the attributes, your HTML tag will be rendered as follows (and you can now dynamically change your attributes values and see them change reactively):</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"projects_section"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"projects"</span>&gt;</span>Dynamically assign a class and an id to the div<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-v-bind-with-boolean-values">V-bind with Boolean values</h3>
<p>With attributes using a boolean value, the v-bind directive works differently. It will show the attribute only if the property's value is true. In all other cases, it won't render the attribute and its content. </p>
<p>For the next example, you will use a button with the disabled attribute.</p>
<p>Inside your root HTML element:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">v-bind:disabled</span>=<span class="hljs-string">"disabled"</span>&gt;</span>You can't click this button<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Inside a Vue instance:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
    <span class="hljs-comment">//disabled: false, // wont render the attribute</span>
    <span class="hljs-comment">//disabled: null, // wont render the attribute</span>
    <span class="hljs-comment">//disabled: undefined, // wont render the attribute</span>
    <span class="hljs-attr">disabled</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">// renders the attribute</span>
}
})
</code></pre>
<p>Only if the disabled property is set to true does the attribute become visible and render its property content.</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">disabled</span>&gt;</span>You can't click this button<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>This is something to keep in mind when working with such attributes.</p>
<p>Another thing to consider is that bindings can include a single JavaScript expression, with some restrictions:</p>
<ul>
<li>only expressions are allowed</li>
<li>only a single expression</li>
<li>no statements</li>
<li>no flow control tools, but the ternary operator works.</li>
</ul>
<p>If you want to read more, visit the documentation 
here:[https://vuejs.org/v2/guide/syntax.html#Using-JavaScript-Expressions]</p>
<p>So far we have seen only two Vue directives, v-html and v-bind. But there are a number of directives available, and here are some more (to list just a few):</p>
<ul>
<li>v-html</li>
<li>v-bind</li>
<li>v-if</li>
<li>v-else-if</li>
<li>v-else</li>
<li>v-for</li>
<li>v-on
All directives have a v- prefix, but there is shorthand for v-bind (:) and v-on (@). </li>
</ul>
<p>They work in the same way. Here's a quick reference for the v-bind and v-on directives: </p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Long syntax --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">v-bind:href</span>=<span class="hljs-string">"url"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Shot syntax --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:href</span>=<span class="hljs-string">"url"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Long syntax with dynamic arguments --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">v-bind:</span>[<span class="hljs-attr">attribute_name</span>]=<span class="hljs-string">"url"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Shot syntax with dynamic arguments --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:</span>[<span class="hljs-attr">attribute_name</span>]=<span class="hljs-string">"url"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Shorthand for v-on</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Long syntax --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">v-on:click</span>=<span class="hljs-string">"runFunction"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Shot syntax --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"runFunction"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Long syntax with dynamic arguments --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">v-on:</span>[<span class="hljs-attr">attribute_name</span>]=<span class="hljs-string">"runFunction"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Shot syntax with dynamic arguments --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> @<span class="hljs-attr">:</span>[<span class="hljs-attr">attribute_name</span>]=<span class="hljs-string">"runFunction"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Now let's see what dynamic arguments are and how they work.</p>
<h3 id="heading-dynamic-arguments-in-vue">Dynamic arguments in Vue</h3>
<p>Directives have been able to have dynamic arguments since Vue 2.6.0. You can use a JavaScript expression in the directive argument if you wrap it inside square brackets.</p>
<p>But there are some restrictions:</p>
<ul>
<li>expressions should evaluate to a string</li>
<li>spaces and quotes are invalid</li>
</ul>
<p>Let's see a practical example</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">v-bind:</span>[<span class="hljs-attr">attribute_name</span>]=<span class="hljs-string">"url"</span>&gt;</span>Visit my Website<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Inside your data object you can define the directive arguments as if they were properties, where the property value is the name of your HTML attribute like <code>hef</code> in the following example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">attribute_name</span>: <span class="hljs-string">'href'</span>,
        <span class="hljs-attr">url</span>: <span class="hljs-string">'https://fabiopacifici.com'</span>
    }
})
</code></pre>
<p>The code above renders the attribute name <code>href</code> and its value dynamically when you bind it using the v-bind directive.</p>
<p>The result will be this:  </p>
<pre><code class="lang-htm">&lt;a href="https://fabiopacifici.com"&gt;Visit my Website&lt;/a&gt;
</code></pre>
<h3 id="heading-dynamic-events-in-vue">Dynamic events in Vue</h3>
<p>You can apply the same concept to event directives like v-on. This directive does the job of the JavaScript event listener. </p>
<p>v-on accepts an argument like click, for example <code>v-on:click="doSomething"</code>.</p>
<p>To apply the concept of dynamicity, let's create a v-on directive and use the square brackets after it to specify a dynamic event.</p>
<p>Inside the index.html file you will place the following code:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">v-on:</span>[<span class="hljs-attr">event_name</span>]=<span class="hljs-string">"runFunction"</span>&gt;</span>Some link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Let's break down the code above. </p>
<p>First you have your root element, the <code>div</code> with an <code>id</code> of <code>app</code>. Inside the root element you add an anchor tag <code>&lt;a&gt;Some link&lt;/a&gt;</code>. </p>
<p>The anchor tag has a <code>v-on</code> directive in it. After the directive you specify a dynamic argument <code>v-on:[event_name]</code> where <code>event_name</code> will be a property inside your Vue instance that you can change as you need. </p>
<p>The v-on directive works like any event listener, so between quotes you need to specify the name of the function that you want to run when the event is triggered, therefore <code>runFunction</code>.</p>
<p>Now, inside your main.js file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
    <span class="hljs-attr">event_name</span>: <span class="hljs-string">"click"</span>
    },
    <span class="hljs-attr">methods</span>: {
        runFunction() {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"test click function"</span>);
        }
    }
})
</code></pre>
<p>Let's review what the code above does. </p>
<p>First, you create the Vue instance. Then you add the <code>event_name</code> property inside the data object and you assign to it a value of <code>click</code>. This is the event you will listen for.</p>
<p>Finally, we said that the v-on directive runs a function when the event is triggered, therefore you need to write a method inside your Vue instance. So inside the methods object, create a new function called <code>runFunction</code> that will simply output a message inside the console. </p>
<p>The power of dynamic events is clear when you replace the value of the <code>event_name</code> property with a different event name.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/LICvNmhsTEs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-methods-in-vue">Methods in Vue</h2>
<p>So far we've learned how to bind data using the v-bind directive inside your template. In the next section, you will learn more directives – but before diving into that, let's quickly talk about how to store your functions. </p>
<p>You can check out the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/5-Methods/">Repository here</a> </p>
<p>And you can see the video version of this section on <a target="_blank" href="https://youtu.be/dESmaEvkZ2I">YouTube</a> if you want to review what you learn.</p>
<p>Since you are working in a big object, the Vue instance function will take the name of the methods. And as you might guess, the Options object has a property called <code>methods</code> where you can store your functions as you do for your data. </p>
<p>Inside your Vue instance, define a method that you can call anything you like – just remember to use a naming convention that clearly describes your code.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">firstName</span>: <span class="hljs-string">"Fabio"</span>,
        <span class="hljs-attr">lastName</span>: <span class="hljs-string">"Pacific"</span> 
    },
    <span class="hljs-attr">methods</span>: {
        <span class="hljs-comment">// es6 syntax</span>
        getFullName(){
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.firstName + <span class="hljs-string">" "</span> + <span class="hljs-built_in">this</span>.lastName;
        }
        <span class="hljs-comment">// es5 syntax</span>
    <span class="hljs-comment">/* getFullName: function(){

        } */</span>
    }
});
</code></pre>
<p>In the code above, you created a method inside the methods object. You called it <code>getFullName</code>. Inside a method, you have access to the <code>this</code> keyword that refers to the object instance, so you can use it to access from a method the properties stored in the data object.</p>
<p>When you call the method <code>getFullName</code> the method will return a single string that contains both the first and the last name. </p>
<p>Now inside your HTML file, you can simply call the method as you did when you needed to access properties in the data object <code>{{ getFullName() }}</code> </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ getFullName() }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now that you know how to create a method and where to put it in the Vue instance, let's move forward and learn more about directives.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/dESmaEvkZ2I" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-conditionals-in-vue-v-ifv-else-ifv-elsev-show">Conditionals in Vue (v-if/v-else-if/v-else/v-show)</h2>
<p>Now it's time to learn more about directives. We will start by looking at how conditionals work in VueJS. The first directive of this section is the <code>v-if</code>, which allows you to render blocks of code based on a certain condition. </p>
<p>You can click to view the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/6-Conditionals/]">Repository here</a>.</p>
<p>And you can click to view the video on <a target="_blank" href="https://youtu.be/VNaCsloA1ZU">YouTube here</a> or use it to review at the end of the section.</p>
<p>Like the <code>if-else</code> statements in vanilla JavaScript, the v-if will check if the returned value of a conditional expression evaluates to true. If so it will render the HTML element and everything you place inside it. </p>
<p>Since it's a directive, it works on a single element (HTML tag). If you want to extend its behaviour on multiple elements, then you need to wrap them inside a <code>&lt;template&gt;</code> tag.</p>
<p>The v-if directive works in the same way as the v-bind directive works: it has access to the properties in the data object and accepts an expression between its quotes. </p>
<p>If the returned value of the expression or the value of the data property you use evaluates to <code>true</code>, then the directive renders the HTML element. Otherwise it doesn't.</p>
<p>Of course, you can check for multiple conditions and end up rendering an element if none of these evaluates to true. You do that using v-if together with the v-else-if and v-else directives.</p>
<p>Let's see a simple example and write some code inside your main.js file to show or hide an element.</p>
<p>The first thing to note is that if you have a property that returns a boolean value, it is enough to use it inside the v-if directive to show/hide an element, like so: </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"showTitle"</span>&gt;</span>{{movieTitle}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<p>And a vue instance with a showTitle property set to true.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">movieTitle</span>: <span class="hljs-string">'Shining'</span>,
        <span class="hljs-attr">showTitle</span>: <span class="hljs-literal">true</span>,
    }
})
</code></pre>
<p>In such a case, you are saying show the title property only if the value of <code>showTitle</code> is <code>true</code>. If you change it to false, the title won't show.</p>
<p>You can put a simple expression inside the quotes of a v-if directive that once computed evaluates to a boolean.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"age &gt;= 18"</span>&gt;</span>{{movieTitle}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
</code></pre>
<p>Inside your main.js file</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">movieTitle</span>: <span class="hljs-string">'Shining'</span>,
        <span class="hljs-attr">age</span>: <span class="hljs-number">18</span>,
    }
})
</code></pre>
<p>In the code above we wrote an expression on the v-if directive that checks if the <code>age</code> property is greater than or equal to 18. If the result is true then the <code>h2</code> will be shown onto the page.</p>
<p>Now let's move to a more complex example and add another condition using the v-else-if.</p>
<h4 id="heading-v-ifv-else-if">v-if/v-else-if</h4>
<p>In the following example, you will first create a v-if condition similar to the one above – but this time you'll check if the user is over 18 but under 21 using the <code>&amp;&amp;</code> operator. </p>
<p>If true, then you'll show the time with an additional note. If false, and the user is over 21, then we will simply show the title of the movie. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"age &gt; 21"</span>&gt;</span>{{movieTitle}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"age &gt; 18 &amp;&amp; age &lt; 21"</span>&gt;</span> {{ movieTitle }} | Watch with an adult<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
</code></pre>
<p>Inside the Vue instance you could have an <code>age</code> property. But to make your simple program dynamic, you can instead use a prompt to ask the user their age. </p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> userAge = <span class="hljs-built_in">Number</span>(prompt(<span class="hljs-string">"What's your age?"</span>))
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">movieTitle</span>: <span class="hljs-string">'Shining'</span>,
        <span class="hljs-attr">age</span>: userAge,
    }
})
</code></pre>
<p>So the code here first asks the user their age, then stores the result as a number inside the variable <code>userAge</code>. </p>
<p>You'll later use the <code>userAge</code> variable inside the data object to assign a value to the <code>age</code> property so that based on its value you will render one element or the other.</p>
<p>Let's move forward and use the v-else directive to show a different message in case the user is under 18.</p>
<h4 id="heading-v-else-directive">v-else directive:</h4>
<p>The <code>v-else</code> directive works differently. You don't have to pass it anything. It simply enters into action when none of the previous conditions evaluate to a true value.</p>
<p>So the new HTML element is fairly simple:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"age &gt; 21"</span>&gt;</span>{{movieTitle}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"age &gt; 18 &amp;&amp; age &lt; 21"</span>&gt;</span> {{ movieTitle }} | Watch with an adult<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">v-else</span>&gt;</span> Sorry You are too young to see this movie<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here we have a <code>p</code> tag with a v-else directive attached. As you can see, it looks like an attribute without values (like the disabled or required HTML attributes).</p>
<p>Your JavaScript file has not changed.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> userAge = <span class="hljs-built_in">Number</span>(prompt(<span class="hljs-string">"What's your age?"</span>))
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">movieTitle</span>: <span class="hljs-string">'Shining'</span>,
        <span class="hljs-attr">age</span>: userAge,
    }
})
</code></pre>
<p>That's all you need to know about conditional rendering to be able to move forward with your first project. But if you want to learn more, here is the documentation: [https://vuejs.org/v2/guide/conditional.html]</p>
<p>You need to learn a few more things before you'll be able to build your first project, which is a simplified Twitter clone. The next topic is about Loops.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/VNaCsloA1ZU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-loops-in-vue">Loops in Vue</h2>
<p>Let's go back to the previous example and learn how to use the v-for directive to output each project of the array onto the page. </p>
<p>You can click to view the Repository <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/7-loops/">here</a></p>
<p>And you can click to view the YouTube-Video <a target="_blank" href="https://youtu.be/aViHg80-7Bs">here</a>, or you can find it at the end of this section to review what you've learned.</p>
<p>For our next task, it would be useful if we could use a loop, and the v-for directive is here to help.</p>
<p>Its syntax doesn't have much in common with a classic <code>for</code> loop in JavaScript, but rather with a Python <code>for in</code> loop or with the <code>for in</code> JavaScript loop used to iterate over objects.</p>
<p>With this directive, you specify the elements of the array and the single element between quotes using the syntax <code>project in projects</code>. Here, projects are the property inside the data object that contains an array of objects, and project is the single element of the array. </p>
<p>You can call this as you like, but keep in mind that what follows the <code>in</code> keyword must be an iterable from your data object while what comes before can be anything you like to refer to each element of the iterable. </p>
<p>In your case, project seems the most appropriate choice since you have an array of projects.</p>
<p>Your JavaScript file will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"John Doe"</span>,
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Portfolio"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"portfolio"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"VueJS"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"grocery shop"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"blog"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"automation script"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"Python"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"eCommerce"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
        ],

    }

});
</code></pre>
<p>Now inside the HTML file, let's use the v-for to render the title of each project.</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{name}} {{title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projects"</span>&gt;</span>{{project.title}}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In the code above, you used <code>{{name}} {{title}}</code> to render the main title for your portfolio. Then you used the v-for directive and specified inside the quests that you want to assign each element of the iteration to a project variable <code>v-for="project in projects"</code>.</p>
<p>Now on each iteration, the <code>project</code> variable holds an object from which you can retrieve its properties using dot notation like so: <code>{{ project.title }}</code>.</p>
<p>One thing to note is that the v-for directive also gives you access to the index of the element at each iteration. You can store it in a variable as you did with the single element you called project. </p>
<p>To do that, you need to wrap them between parentheses and separate the element and its index with a comma, like so <code>v-for="(project, index) in projects"</code>. </p>
<p>Also, note that when working with objects Vue can show an alert to inform you that the use of a key is recommended. This means that it expects a key to identify each element when it's rendered. </p>
<p>You can do this using the <code>key</code> attribute and bind it, for instance to an id property on the object or to another different property, like so</p>
<pre><code class="lang-html">
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{name}} {{title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projects"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"project.title"</span>&gt;</span>{{project.title}}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here you used the v-bind shorthand directive to bind the key attribute to the project.id property if it exists or to another property if not. </p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"John Doe"</span>,
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Portfolio"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"portfolio"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"VueJS"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"grocery shop"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"blog"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"automation script"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"Python"</span>]},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"eCommerce"</span>, <span class="hljs-attr">languages</span>: [<span class="hljs-string">"HTML"</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-string">"PHP"</span>]},
        ],

    }

});
</code></pre>
<p>v-for can also be used to iterate over objects. In such a case, you have access to the value, the key, and also the index like so <code>v-for="(value, key, index) in object"</code> where 'object' is a property in the data object.</p>
<p>If you want to learn more, visit the documentation here: [https://vuejs.org/v2/guide/list.html]</p>
<p>Let's now move on to another important feature of Vue: how to handle user inputs and events. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/aViHg80-7Bs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-handle-user-input-with-event-handling-v-on-in-vue">How to Handle User Input with Event Handling (v-on) in Vue</h2>
<p>To make the application react to a user's input, Vue provides a straightforward directive called <code>v-on</code>. This is one of the directives that accepts arguments, similar to the v-bind directive. </p>
<p>With such a directive, it's easy to listen for events triggered by a user.</p>
<p>The v-on directive lets you run a function that executes a block of code when the user performs an action, like when they click on a button, hover on an element, or press a specific key on the keyboard.</p>
<p>You can check out the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/8-user-inputs-events-handling/">Repository here</a>.</p>
<p>And you can view the video on <a target="_blank" href="https://youtu.be/9_U1eagqOJY">YouTube here</a> or at the end of this section to review what you've learned.</p>
<h3 id="heading-v-on-syntax-and-events">V-on Syntax and Events</h3>
<p>There are two types of syntax we can use, the long-form or the short. They're equivalent, so pick the one you prefer. What follows is just a representation of the syntax, and I'll explain it in detail in a minute.</p>
<p>Long syntax: <code>v-on:EventName='doSomething'</code>
Shot syntax: <code>@EventName='doSomething'</code></p>
<p>There are many events you can listen to, such as: </p>
<ul>
<li>click</li>
<li>submit</li>
<li>mouseover</li>
<li>mouseenter</li>
<li>mouseleave</li>
<li>keyup</li>
<li>keydown</li>
<li>keypress</li>
</ul>
<p>But you can also create custom events (which you will see when you reach the components section).</p>
<p>Let's pick the long-form syntax: <code>v-on:EventName='doSomething</code>. I'll explain it more now.</p>
<p>First, you have the directive <code>v-on</code>. Then you have an argument that is the event name you want to listen for, like <code>click</code>. After that, the <code>doSomething</code> can be any method that you have defined inside the methods object of the Vue instance.</p>
<p>This method is like any other function that you define inside a JavaScript object. It can have parameters or not. If it has them, you can call the method and pass parameters to it as usual like this: <code>doSomething(param, param_2, param3)</code>. </p>
<p>You can have something like this <code>&lt;div v-on:click="likeProject"&gt;Like&lt;/div&gt;</code> and when the user clicks on this element, it will trigger a method and run some code to increase a like counter inside a project.</p>
<p>Let's first create the HTML you need for that:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"projects"</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(project,index) in projects"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{project.title.toUpperCase()}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Like
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-heart fa-lg fa-fw"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"likeProject(index)"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
        {{project.likes}}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In the code here, first you'll use the v-for directive to loop over the array of projects. Note that you should use the syntax <code>(project, index) in projects</code> because you will need to pass the index to the like method that you defined earlier. </p>
<p>After that, you output some data onto the page (like the project name in uppercase letters) then the description, and a <code>div</code> tag with an icon for the likes (remember to add font awesome to get the icon). </p>
<p>On the heart icon, add the directive v-on using the short syntax <code>@click="likeProject(index)"</code> between quotes that you used to invoke your <code>likeProject(index)</code> method. Then pass to it the index as a parameter so you can find the current project the user clicked on. </p>
<p>Finally, you'll render the likes onto the page for the current project using the <code>{{project.likes}}</code> syntax.</p>
<p>Now it's time to go in the Vue instance and write your method.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>:<span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"My first project"</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">"A simplified Twitter clone"</span>, <span class="hljs-attr">likes</span>: <span class="hljs-number">0</span>},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"My second project"</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">"Projects portfolio with GitHub"</span>, <span class="hljs-attr">likes</span>: <span class="hljs-number">0</span>},
        ]
    },
        <span class="hljs-attr">methods</span>: {
            likeProject(index){
                <span class="hljs-keyword">const</span> project = <span class="hljs-built_in">this</span>.projects[index]
                project.likes++
                <span class="hljs-built_in">console</span>.log(project.likes)
            }

    }
});
</code></pre>
<p>As I said earlier, you needed to define a method to call when the user clicks on a link. So you create the <code>likeProject</code> method, which accepts a parameter that will be the index of the element the user clicked on. </p>
<p>You can then add a likes property inside your projects array and access it for the current project to increment its value every time the user clicks on your link.</p>
<h3 id="heading-how-to-access-the-original-event">How to access the original event</h3>
<p>If for any reason you need to access the original DOM event, you could have used the special <code>$event</code> variable inside the method like this on the v-on directive: <code>doSomething(param1, param2, $event)</code>. Let's see an example of that now.</p>
<p>You need to add the special variable in the method call on your v-on directive like so:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-heart fa-lg fa-fw"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"likeProject(index, $event)"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
</code></pre>
<p>Then you can access the original event inside your method like so: </p>
<pre><code class="lang-js">likeProject(index, event){
    <span class="hljs-built_in">console</span>.log(event); <span class="hljs-comment">// get the original event</span>
    <span class="hljs-keyword">const</span> project = <span class="hljs-built_in">this</span>.projects[index]
    project.likes++
    <span class="hljs-built_in">console</span>.log(project.likes)
}
</code></pre>
<p>Now that you know how the v-on directive works, let's improve our Likes example and put something more in it. We will use key modifiers in the next example, so let's quickly see what they are and what you can do with them.</p>
<h3 id="heading-event-modifiers-in-vue">Event Modifiers in Vue</h3>
<p>With events, Vue provides access to a number of Event modifiers. They are divided into 4 main groups. You can add these modifiers to a directive to change the way your event behaves. They are like postfix and you can chain them using dot notation. </p>
<p>Below there is a quick reference.</p>
<p>Categories:</p>
<ul>
<li>event modifiers</li>
<li>key modifiers</li>
<li>system modifiers keys</li>
<li>mouse buttons modifiers</li>
</ul>
<p>Event Modifiers:
.stop
.prevent 
.capture
.self
.once
.passive</p>
<p>Key Modifiers:
You can add these modifiers to the @keyup listener to listen for when these keys are pressed or use them as a combination with the @click event to listen for a click+space, for example. <code>@click.enter="doSomething"</code></p>
<p>.enter
.tab
.delete (captures both “Delete” and “Backspace” keys)
.esc
.space
.up
.down
.left
.right</p>
<p>System modifiers:
With these modifiers, you can trigger mouse or keyboard event listeners when the corresponding key is pressed.
.ctrl 
.alt
.shift
.meta
.exact (allows control of the exact combination of system modifiers needed to trigger an event)</p>
<p>Mouse buttons modifiers:
These modifiers allow you to trigger a mouse event listener if the corresponding mouse button is clicked. </p>
<p>.left
.right
.middle</p>
<p>If you want to learn more, read the docs <a target="_blank" href="https://vuejs.org/v2/guide/events.html#Event-Modifiers">here</a>.</p>
<h3 id="heading-how-to-like-a-project-with-key-modifiers">How to like a project with key modifiers</h3>
<p>In the previous example, you used the v-on:click directive to trigger a mouse event listener that aimed to simulate a like on a project. </p>
<p>But the user was able to add as many likes they wanted by clicking on the icon. </p>
<p>In the next example, you will do things a bit differently.</p>
<ul>
<li>First, you will prevent the user from adding more than one like to each project,</li>
<li>Then you will let the user remove a like </li>
<li>Finally, you will keep the likes on the page even after the user refreshes the page.</li>
</ul>
<p>Let's get started. This time you will use mouse button modifiers to listen for clicks. The left mouse button click will trigger the add like behaviour and the right mouse button click will trigger the remove behaviour.</p>
<p>Inside your HTML file: </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Users can like a project with a left click and dislike it with right click --&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"projects"</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projects"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{project.title.toUpperCase()}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Like 
                <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-heart fa-lg fa-fw"</span> 
                    @<span class="hljs-attr">click.left</span>=<span class="hljs-string">"addLike(project)"</span> 
                    @<span class="hljs-attr">click.right</span>=<span class="hljs-string">"removeLike(project, $event)"</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span> 
               {{project.likes}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>


<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In the code above you have taken what you had before and simply added a left mouse button key modifier to the click event <code>@click.left</code>. Then you invoked the <code>addLike</code> method. This will make your project like counter increase by one as we have seen before. </p>
<p>Then you added another event listener to the same element, but this time you used the <code>.right</code> mouse button key modifier to listen when the user clicks on our icon using the right button <code>@click.right="removeLike()"</code>. </p>
<p>In the remove like method, you have also passed the special variable $event so that you can use the original event later in your method to prevent its default behaviour and open the contextual menu. </p>
<p>But we said earlier that you can also chain key modifiers and indeed there is a <code>.prevent</code> key modifier that you can use here instead of the <code>$event</code> variable. You could do the same like this: <code>@click.right.prevent="removeLike(project)"</code> </p>
<p>Let's see how to structure your main.js file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"John Doe"</span>,
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Portfolio"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"My first project"</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">"A simplified Twitter clone"</span>, <span class="hljs-attr">likes</span>: <span class="hljs-number">0</span>},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"My second project"</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">"Projects portfolio with GitHub"</span>, <span class="hljs-attr">likes</span>: <span class="hljs-number">0</span>},
        ]
    },
    <span class="hljs-attr">methods</span>: {
        addLike(project){
           <span class="hljs-built_in">console</span>.log(project)  
        },
        removeLike(project, event){
            <span class="hljs-built_in">console</span>.log(project)
            <span class="hljs-built_in">console</span>.log(event)
        }
    }

});
</code></pre>
<p>So in the data object, you have a <code>projects</code> property that is an array of objects. Each object has a likes property that you will increment or decrement depending on what mouse button the user clicks.</p>
<p>Inside the <code>methods</code> object, you created the two methods you referenced in your v-on directives <code>addLike()</code> and <code>removeLike()</code>. For now, you are only logging to the console the project parameter value and the event value. You will implement the logic in a minute.</p>
<p>Let's start with the add likes method – it could look like this:</p>
<pre><code class="lang-js">addLike(project){
    <span class="hljs-keyword">const</span> projectTitle = project.title;
    <span class="hljs-keyword">if</span>(!<span class="hljs-built_in">localStorage</span>.getItem(projectTitle)) {
        project.likes++;
        <span class="hljs-built_in">localStorage</span>.setItem(projectTitle, <span class="hljs-literal">true</span>);
    }              
}
</code></pre>
<p>There are a few things going on here. In the first line, you're storing the project title inside the <code>projectTitle</code> variable. Then, you said you wanted data to persist if you refresh the page so you are using the <code>localStorage</code> API to store information inside the client browser. </p>
<p>You increment the likes count by one, but you do that depending on a value inside the local storage. </p>
<p>You can do this by first checking to see if there is a key in the <code>localStorage</code> matching your project title, <code>if(!localStorage.getItem(projectTitle))</code>. </p>
<p>If this evaluates to false, then you will run the code inside the if block and first increment the likes <code>project.likes++</code>. </p>
<p>Second, use the <code>.setItem()</code> method of the local storage API to set a key-value pair with the project title as the key and a boolean value as its value <code>localStorage.setItem(projectTitle, true)</code>.</p>
<p>To put an item in the local storage, you'll use <code>localStorage.setItem()</code>. The set item method accepts a key-value pair. Your key will be the title you saved in the variable <code>projectTitle</code> and the value will the boolean value <code>true</code>.</p>
<p>Now let's see if this works. </p>
<pre><code class="lang-js">removeLike(project, event){
    event.preventDefault(); <span class="hljs-comment">// This can be omitted if we use the prevent key modifier</span>
    <span class="hljs-keyword">const</span> projectTitle = project.title;
    <span class="hljs-keyword">if</span>(project.likes &gt; <span class="hljs-number">0</span> &amp;&amp; <span class="hljs-built_in">localStorage</span>.getItem(projectTitle)) {
        project.likes--;
        <span class="hljs-built_in">localStorage</span>.removeItem(projectTitle);
    }
}
</code></pre>
<p>This function does the opposite of the previous. When the user clicks their right mouse button, the method <code>removeLikes()</code> is executed and you do the following:</p>
<p>First things first, you need to prevent its default behaviour. Otherwise when the user right-clicks on the icon, the contextual menu will pop up and we don't want that. So, you'll use the <code>event.preventDefault()</code> method on the original event that is represented by the <code>event</code> parameter on your method. </p>
<p>Alternatively, you can omit this if you use the prevent key modifier in the v-on directive <code>@click.right.prevent="removeLike(project)</code>.</p>
<p>The next step is to grab the project title. Since you also passed a parameter to the method to represent the current project object <code>removeLike(project, event)</code>, you can store the project title in a variable <code>projectTitle</code>.</p>
<p>Then you need to make a couple of checks. First, you want to decrement the likes only if its value is greater than zero. Then you want to make sure the project title is in the local storage as a key with a value. </p>
<p>So, in your condition, you have done both checks <code>if(project.likes &gt; 0 &amp;&amp; localStorage.getItem(projectTitle))</code>. Now, if both conditions evaluate to true, the code inside the if block can run. </p>
<p>First you remove the like by decrementing its value <code>project.likes--</code>. Then you remove the project title from the local storage using the <code>removeItem</code> method and pass to it the key you want to remove (which is the project title <code>localStorage.removeItem(projectTitle)</code>).   </p>
<p>To put it all together, you should now have the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"John Doe"</span>,
        <span class="hljs-attr">title</span>: <span class="hljs-string">"Portfolio"</span>,
        <span class="hljs-attr">projects</span>: [
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"My first project"</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">"A simplified Twitter clone"</span>, <span class="hljs-attr">likes</span>: <span class="hljs-number">0</span>},
            {<span class="hljs-attr">title</span>: <span class="hljs-string">"My second project"</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">"Projects portfolio with GitHub"</span>, <span class="hljs-attr">likes</span>: <span class="hljs-number">0</span>},
        ]
    },
        <span class="hljs-attr">methods</span>: {
        addLike(project)
        {
            <span class="hljs-comment">//console.log(project, "like");</span>
            <span class="hljs-keyword">const</span> projectTitle = project.title;
            <span class="hljs-comment">// check if the current project is not in the local storage</span>
            <span class="hljs-keyword">if</span>(!<span class="hljs-built_in">localStorage</span>.getItem(projectTitle)) {
                <span class="hljs-comment">// set the item in the storage and increase the likes counter</span>
                project.likes++;
                <span class="hljs-built_in">localStorage</span>.setItem(projectTitle, <span class="hljs-literal">true</span>);
            }

        },
        removeLike(project){ 
            <span class="hljs-keyword">const</span> projectTitle = project.title;
            <span class="hljs-built_in">console</span>.log(project, <span class="hljs-string">"dislike"</span>);  
            <span class="hljs-keyword">if</span>(project.likes &gt; <span class="hljs-number">0</span> &amp;&amp; <span class="hljs-built_in">Boolean</span>(<span class="hljs-built_in">localStorage</span>.getItem(projectTitle))) {
                project.likes--;
                <span class="hljs-built_in">localStorage</span>.removeItem(projectTitle);
            }

        }
    },
    mounted(){
        <span class="hljs-built_in">this</span>.projects.forEach(<span class="hljs-function"><span class="hljs-params">project</span> =&gt;</span> {
            <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(project.title) !== <span class="hljs-literal">null</span>) {
                project.likes = <span class="hljs-number">1</span>; 
            }
        });
    }

});
</code></pre>
<p>To make the code work, you also need to add a life cycle hook called mounted. This will let you run code when the root element is mounted on the Vue instance. With it, you can check if the localStorage has a key corresponding to your project title and if so, update the value of the likes counter.</p>
<p>And your HTML is still the same:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Users can like a project with a left click and dislike it with right click --&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"projects"</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projects"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{project.title.toUpperCase()}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Like 
            <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-heart fa-lg fa-fw"</span> 
                @<span class="hljs-attr">click.left</span>=<span class="hljs-string">"addLike(project)"</span> 
                @<span class="hljs-attr">click.right</span>=<span class="hljs-string">"removeLike(project, $event)"</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span> 
            {{project.likes}}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Remember that you can get rid of the <code>$event</code> variable passed to the <code>removeLike</code> method by using the event key modifier like so: <code>@click.right.prevent="removeLike(project)"</code></p>
<p>You have learned a lot so far! And now that you have seen key modifiers in action, we can move forward to the next topic: two-way model binding and the v-model directive. Then we'll start building our Twitter clone. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/9_U1eagqOJY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-two-way-model-binding-v-model-in-vue">Two Way Model Binding (v-model) in Vue</h2>
<p>All right, so far we have seen how to bind properties from the data object to our HTML tags and inside attributes, 
how to loop over a sequence of elements and, how to display conditionally elements onto our template with conditionals. </p>
<p>We have covered how to define methods inside the methods object so that we can perform more complex operations on our data and, 
we have learned how to work with events using the v-on directive.</p>
<p>In the next section, we will look at how Vue opens a two-way communication channel between a form's input and, a property defined
inside the data object. Then we will use this knowledge to build our first project together.</p>
<p>You can check out the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/9-two-way-binding/">Repositoy here</a>.</p>
<p>And you can view the video on <a target="_blank" href="https://youtu.be/pBUXTUvDRCo">YouTube here</a> or at the end of the section if you want to review what you've learned.</p>
<h3 id="heading-how-does-the-v-model-directive-work">How does the v-model directive work?</h3>
<p>The v-model is another Vue directive. You can use it out of the box, and it's useful to simplify the way an input tag can communicate 
with a Vue instance's property in the data object. </p>
<p>It works like all the other directives. The main difference is that when it's implemented, your application will listen for changes 
inside the input with this v-model directive and update the attached property's value immediately inside the data object and vice-versa. </p>
<p>It is effectively a two-way communication channel between your template and the Vue instance. It's the Vue way to interact with user input and simplify your life as a developer.</p>
<p>Let's look at a straightforward example.</p>
<h3 id="heading-how-to-use-the-v-model-on-an-input-tag">How to use the v-model on an input tag</h3>
<p>First, you need an input tag inside the element you defined as the root element in the Vue instance, the div with an id of <code>app</code>. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you want to tweet about today?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">placehoder</span>=<span class="hljs-string">"What's happening today?"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In the HTML you have an input tag, which has the v-model directive attached to it as an HTML attribute. Anything between quotes is computed as a JavaScript expression, so you write the name of a property <code>tweet</code> that you will create inside the Vue data object.</p>
<p>So let's do it.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">tweet</span>: <span class="hljs-string">""</span>
    }
});
</code></pre>
<p>So now you have a Vue instance and, in it, you have a data object with a tweet property that has an empty string as its value. </p>
<p>If you open the console and inspect the Vue element, you can see the two-way data binding in action. </p>
<p>By changing the value of the tweet property, you will immediately update the value inside the input tag and vice-versa. </p>
<p>You have this <code>tweet</code> property in the data object and you already know how to render its content onto the page. So now you can update your markup and add a paragraph under the input tag to see the value dynamically changing while you type.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you want to tweet about today?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">placehoder</span>=<span class="hljs-string">"What's happening today?"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{tweet}}<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>How cool is that? Now you can see the tweet property changing in real-time as you type. </p>
<p>That's the two-way data binding. If you change the content of the tweet property directly it will be reflected in your template, too.</p>
<p>If you want to learn more, make sure to read the official <a target="_blank" href="https://vuejs.org/v2/guide/forms.html">Documentation</a> too.</p>
<h3 id="heading-how-to-build-a-tweet-box">How to build a tweet box</h3>
<p>Now, let's raise the bar a little and build something together.</p>
<ul>
<li>We will create a simple <code>textarea</code> with a submit button, </li>
<li>We will display the number of characters the user has left while they are typing so that they can submit the form without exceeding the max number of characters allowed. </li>
<li>Like in a tweet, the maximum number of characters will be 200.</li>
</ul>
<h4 id="heading-how-to-define-the-initial-markup">How to define the initial markup</h4>
<p>Now you need to define a markup. So inside our index.html file, write the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you want to tweet about today?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"submitData"</span>&gt;</span>
       <span class="hljs-comment">&lt;!-- Code here --&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- More code here --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>First you have first created your root element for the Vue instance so that it can monitor the markup and do its magic.</p>
<p>Then you created a form tag with an event listener using the directive v-on, which listens for the submit event and runs a function <code>submitData</code> that you still have to create.</p>
<p>You also added the <code>.prevent</code> modifier so that the page doesn't refresh when you submit the form.</p>
<h4 id="heading-how-to-define-the-vue-instance-and-methods">How to define the Vue instance and methods</h4>
<p>Let's define our Vue instance and create the <code>submitData</code> method so that you can use it later when you need it.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-comment">// data object props here</span>
    },

    <span class="hljs-attr">methods</span>: {
          submitData(){
             <span class="hljs-comment">// Code here</span>
        }
    },

});
</code></pre>
<h4 id="heading-how-to-add-a-text-area-and-a-submit-button">How to add a text area and a submit button</h4>
<p>Now back to the HTML: let's add the text area inside your form. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you want to tweet about today?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"submitData"</span>&gt;</span>
       <span class="hljs-comment">&lt;!-- Code here --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"80"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"200"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- More code here --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Inside the form tag, you create a label and a <code>textarea</code> for your tweet box. 
On the <code>textarea</code> you use the directive v-model to bind the <code>textarea</code> value to a <code>tweet</code> property and vice-versa. So now when one changes the other changes, too. </p>
<p>NOTE: The v-model directive is used on form elements like inputs, text areas, check box, and more.</p>
<p>After the <code>textarea</code> you put a button of type submit so that when a user clicks it the form's data are sent to your application's <code>submitData()</code> method and you can process them.</p>
<h4 id="heading-how-to-add-properties-to-the-vue-instance">How to add properties to the Vue instance</h4>
<p>Now inside your JavaScript file, you need to create the tweet property in the data object and do something with this information so that you can later show a list of tweets sent. </p>
<p>We also said that we want to limit the characters to 200 and show an error when they're in excess.</p>
<p>So let's add a few more properties here like:</p>
<ul>
<li><code>tweet</code> for the current tweet message that the user inputs in the text area</li>
<li><code>tweets</code> for the list of tweets</li>
<li><code>max_length</code> for the characters limit</li>
</ul>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">tweets</span>: [],
        <span class="hljs-attr">tweet</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">200</span>,  
    },

    <span class="hljs-attr">methods</span>: {
          submitData(){
              <span class="hljs-comment">/* Handle the tweet */</span>
        }
    },

});
</code></pre>
<p>So now with the tweets property as an array and using the two-day binding between the tweet property and the <code>textarea</code>, you can push all tweets inside the <code>tweets</code> array when the user submits the form by triggering the 
<code>submitData</code> method.</p>
<h4 id="heading-how-to-implement-the-character-counter">How to implement the character counter</h4>
<p>Before implementing the <code>submitData</code> method, you can show a character counter while the user types in the textarea. </p>
<p>Let's implement this feature so the user knows if they can submit the tweet or not.</p>
<p>Back in the HTML file, you can add a div with a couple of span elements and use a v-if directive to check the length of the character. It'll show the counter while the user is within the characters limit, otherwise it'll show an error message.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you want to tweet about today?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"submitData"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"80"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>        
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Show character limits here --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ `Max: ${tweet.length} of ${max_length} characters` }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{`Max char limit reached! excess chars: ${max_length - tweet.length}`}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The code above uses two-way data binding between the tweet property and the <code>textarea</code> to find out if the user has reached the character limit that you defined as the <code>max_lenght</code> property. </p>
<p>Since the tweet property is connected to the <code>textarea</code>, you can use the <code>v-if</code> directive combined with the <code>tweet.length</code> and the <code>max_length</code> properties to make the comparison. </p>
<p>Now, every time the user types something in the <code>textarea</code>, the string saved in the <code>tweet</code> property increases by one character. Then you can use the <code>.length</code> property to see how long the whole string is and compare it against your <code>max_length</code> property.</p>
<p>You use the directive  <code>v-if="tweet.length &lt;= max_length"</code> to make your comparison. When this comparison returns true, the user will see the span tag with its content, the counter. </p>
<p>Inside the span tag, you used the moustache syntax to show the user the current length of the property <code>tweet</code> and the character limit.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ `Max: ${tweet.length} of ${max_length} characters` }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<p>After the <code>v-if</code> directive, a <code>v-else</code> directive handles the error message that you show to the user when there are no characters left to use. </p>
<p>Here the content of the span element shows a message that tells how many characters there are in excess by subtracting the tweet length from the <code>max_lenght</code> property.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{`Max char limit reached! excess chars: ${max_length - tweet.length}`}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<h4 id="heading-how-to-submit-the-form">How to submit the form</h4>
<p>All that's left is to add the tweet to the list of tweets and show them on the page when the user submits the form.</p>
<p>Let's complete the <code>submitData</code> method so that every time it's executed it pushes a new object to the tweets array. </p>
<p>Inside the methods object the <code>submitData</code> methods now looks like this:</p>
<pre><code class="lang-js"> submitData(){
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.tweet.length &lt;= <span class="hljs-built_in">this</span>.max_length) {
        <span class="hljs-built_in">this</span>.tweets.unshift(<span class="hljs-built_in">this</span>.tweet);
        <span class="hljs-built_in">this</span>.tweet = <span class="hljs-string">""</span>;
    } 
}
</code></pre>
<p>The method above first checks if the length of the <code>tweet</code> property is less than or equal to the <code>max_length</code> property. If the condition evaluates to true, then you can add the <code>tweet</code> content to the array using the <code>unshift</code> method (which adds it to the beginning of the array).</p>
<p>Finally, you need to clear the value of the <code>tweet</code> property. You can do this by assigning to it an empty string again.</p>
<p>NOTE that since you are inside a method, you need to use the <code>this</code> keyword to grab properties and eventually methods inside the Vue instance.</p>
<h4 id="heading-how-to-show-a-list-of-tweets">How to show a list of tweets</h4>
<p>Now, you can also show a list of tweets in your template. </p>
<p>To do that you will use a <code>v-for</code> directive and loop over the <code>tweets</code> array to show each tweet.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"text in tweets"</span>&gt;</span>{{text}}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<h3 id="heading-put-it-all-together">Put it all together</h3>
<p>The final code now looks like this:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>VueJs v-model<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Fontawesome CDN --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://use.fontawesome.com/releases/v5.1.1/css/all.css"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- VueJS CDN --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you wanna tweet about today<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Tweet form --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"submitData"</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Alert the user  --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my-3"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span>
                {{ ` Max: ${tweet.length} of ${max_length} characters` }}
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">v-else</span>&gt;</span> {{ `Max char limit reached! excess characters: ${max_length -
                tweet.length} ` }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Tweets message --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"tweet in tweets"</span>&gt;</span>
                {{tweet}}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Our final javascript file </p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">tweet</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">tweets</span>: [],
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">200</span>        
    }, 
    <span class="hljs-attr">methods</span>: {
        submitData(){
            <span class="hljs-comment">// Handle the tweet submission</span>
            <span class="hljs-keyword">if</span>(<span class="hljs-built_in">this</span>.tweet.length &lt;= <span class="hljs-built_in">this</span>.max_length){
                <span class="hljs-built_in">this</span>.tweets.unshift(<span class="hljs-built_in">this</span>.tweet);
                <span class="hljs-built_in">this</span>.tweet = <span class="hljs-string">""</span>;
            }
        }
    }
})
</code></pre>
<h3 id="heading-improvements-you-can-make">Improvements you can make</h3>
<p>If you take this bit of code from your index.html file, there is something you can do to clean up our code... </p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Show the max char messages --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ `Max: ${tweet.length} of ${max_length} characters` }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{`Max char limit reached! excess chars: ${max_length - tweet.length}`}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>To clean this template file, we can follow two approaches that are exactly the same, except that one is cached and the other one isn't. </p>
<ul>
<li>Computed Properties (cached)</li>
<li>Methods (not cached)</li>
</ul>
<p>In the next section, we will learn what computed properties are and how they differ from methods.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/pBUXTUvDRCo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-computed-properties-and-methods">Computed Properties and methods</h2>
<p>You should use computed properties instead of in-template expressions for complex logic that has the scope of changing the presentation of our data, not the data itself. </p>
<p>If we need to change the data, then you should use methods instead. Computed properties are cached based on their dependencies, meaning that it will re-evaluate only when its dependencies have changed. </p>
<p>With computed properties, the result of the previously run function is returned if the dependencies have not changed. </p>
<p>You can view the <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/10-computed-properties/">repository here</a> and watch the video on <a target="_blank" href="https://youtu.be/VxFT6cgTHhw">YouTube here</a>. The video is also listed at the end of this section so you can review what you've learned.</p>
<p>In the following example, we will use computed properties but we could also use methods. Generally speaking, we use computed properties when we have an expensive operation that we want to execute and cache so that the next time we don't have to run it again unless something has changed.  </p>
<p>Let's implement a computed property for the following messages. Our HTML file will now change from this:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Show the max char messages --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ `Max: ${tweet.length} of ${max_length} characters` }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{`Max char limit reached! excess chars: ${max_length - tweet.length}`}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>to this much cleaner version:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Show the max char messages --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ maxCharsText }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{errorMessage}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>We have replaced the contents of both spans with two new properties that will be placed as methods inside our computed object.</p>
<p>Now inside our Vue instance, we will create a new object called <code>computed</code> where we will define two methods that will return the messages we had before. </p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">tweets</span>: [],
        <span class="hljs-attr">tweet</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">200</span>,  
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>
    },
    <span class="hljs-comment">// Computed Properties</span>
 <span class="hljs-attr">computed</span>: {
        <span class="hljs-attr">maxCharsText</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            <span class="hljs-keyword">return</span> <span class="hljs-string">`Max: <span class="hljs-subst">${<span class="hljs-built_in">this</span>.tweet.length}</span> of <span class="hljs-subst">${<span class="hljs-built_in">this</span>.max_length}</span> characters`</span>;
        },
        <span class="hljs-attr">errorMessage</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            <span class="hljs-keyword">return</span> <span class="hljs-string">`Max char limit reached! excess chars: <span class="hljs-subst">${<span class="hljs-built_in">this</span>.max_length - <span class="hljs-built_in">this</span>.tweet.length}</span>`</span>
        }
    },
    <span class="hljs-comment">// Methods</span>
 <span class="hljs-attr">methods</span>: {
          submitData(){
              <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.tweet.length &lt;= <span class="hljs-built_in">this</span>.max_length) {
                  <span class="hljs-built_in">this</span>.tweets.unshift(<span class="hljs-built_in">this</span>.tweet);
                  <span class="hljs-built_in">this</span>.tweet = <span class="hljs-string">""</span>;
              } 
        }
    },

});
</code></pre>
<p>The first method <code>maxCharsText</code> returns exactly the same string we had before inside our HTML file. The only difference is that we are using the keyword <code>this</code> to reference the properties we needed to grab inside the Vue instance <code>this.tweet.length</code> and <code>this.max_length</code>. </p>
<p>The second method works in the exact same way and it also uses the keyword <code>this</code> to pick the properties defined in the Vue instance <code>this.max_length</code> and <code>this.tweet.length</code>.</p>
<h3 id="heading-all-together">All together</h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>What do you want to tweet about today?<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"submitData"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"80"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Next<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ maxCharsText }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{errorMessage}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"text in tweets"</span>&gt;</span>{{text}}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>JavaScript file</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">tweets</span>: [],
        <span class="hljs-attr">tweet</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">200</span>,  
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>
    },
    <span class="hljs-comment">// Computed Properties</span>
 <span class="hljs-attr">computed</span>: {
        <span class="hljs-attr">maxCharsText</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            <span class="hljs-keyword">return</span> <span class="hljs-string">`Max: <span class="hljs-subst">${<span class="hljs-built_in">this</span>.tweet.length}</span> of <span class="hljs-subst">${<span class="hljs-built_in">this</span>.max_length}</span> characters`</span>;
        },
        <span class="hljs-attr">errorMessage</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            <span class="hljs-keyword">return</span> <span class="hljs-string">`Max char limit reached! excess chars: <span class="hljs-subst">${<span class="hljs-built_in">this</span>.max_length - <span class="hljs-built_in">this</span>.tweet.length}</span>`</span>
        }
    },
    <span class="hljs-comment">// Methods</span>
 <span class="hljs-attr">methods</span>: {
          submitData(){
              <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.tweet.length &lt;= <span class="hljs-built_in">this</span>.max_length) {
                  <span class="hljs-built_in">this</span>.tweets.unshift(<span class="hljs-built_in">this</span>.tweet);
                  <span class="hljs-built_in">this</span>.tweet = <span class="hljs-string">""</span>;
              } 
        }
    },

});
</code></pre>
<p>If we want to use methods instead of computed properties, we can simply move both methods from the <code>computed</code> object inside the <code>methods</code> object and invoke them with parenthesis inside our HTML file like so:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweet.length &lt; max_length"</span>&gt;</span> {{ maxCharsText() }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"errorMessage"</span> <span class="hljs-attr">v-else</span>&gt;</span>{{errorMessage() }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Just remember that computed properties are cached while methods are not. 
If you want to learn more make sure to read the official <a target="_blank" href="https://vuejs.org/v2/guide/computed.html">documentation</a>.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/VxFT6cgTHhw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-create-a-simple-twitter-clone">How to Create a Simple Twitter Clone</h2>
<p>Now, let's put together everything we've learned so far and and build our very first project. It will be a minimalist and simplified twitter-like web application. </p>
<p>We want to create a simple application that has some kind of registration form, a box to add new tweets, and a section where we can show all tweets. We also want to be able to remove tweets.</p>
<p>All data must be persistent so that after the page is refreshed the list of tweets is still visible while the registration form will be hidden.</p>
<p>You can watch the video on <a target="_blank" href="https://youtu.be/v1j_bDDd6jI">YouTube here</a> or at the end of this section if you want to review.</p>
<p>You can also view the repository <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/11-project-simple-twitter-cone/">here</a>.</p>
<h3 id="heading-define-our-tasks">Define our tasks</h3>
<p>Let's break this down into large tasks first. Then we will see what we need to do to complete each one. </p>
<ul>
<li>create a registration form</li>
<li>create a tweets box form</li>
<li>create a tweets section</li>
</ul>
<p>To do our project we need to research what tools we need to use to achieve our goals, so lets put them down:</p>
<ul>
<li>VueJS (application logic)</li>
<li>localStorage (make data persistent)</li>
<li>font awesome (icons)</li>
</ul>
<p>This application has no database so we are unable to record multiple users and their tweets. It's just a proof of concept, something we build to use our new knowledge.</p>
<h3 id="heading-create-the-project-structure">Create the project structure</h3>
<p>Now that we know what to do, let's start by creating our project structure and importing the tools we need to complete the first task, the registration form.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Simple tweetter clone<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- CDN Fontawesome --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span> /&gt;</span>

    <span class="hljs-comment">&lt;!-- VueJS development version, includes helpful console warnings --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Style sheet --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Register an account --&gt;</span>

    <span class="hljs-comment">&lt;!-- Add a tweet --&gt;</span>

    <span class="hljs-comment">&lt;!-- Show all tweets --&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Link our main.js file --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Now that our HTML file is ready, let's create the main.js file and create a Vue instance.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {

    },
    <span class="hljs-attr">methods</span>: {

    }

});
</code></pre>
<p>Finally, we need to create a style.css file that we will place for now in the root folder of our project. </p>
<p>We will use a CSS file that I have already written, and you can download it from <a target="_blank" href="https://bitbucket.org/fbhood/simple-tweet-app/src/master/style.css">here</a>.</p>
<p>OK, our basic structure is ready to go. Inside our HTML file, we have some comments that reflect our 3 main tasks: create a registration form, create an add tweet box and, show a list of tweets. </p>
<p>Let's start with the first task and simulate a registration form.</p>
<h3 id="heading-how-to-simulate-a-registration-form-html">How to simulate a registration form - HTML</h3>
<p>Inside the root element <code>&lt;div id="app"&gt;&lt;/div&gt;</code> we need to create a registration form with the following fields: name, email, password, and a submit button. The form is contained in a card so we will wrap everything in a div and assign to it a card class. </p>
<p>The form won't submit data to a server, but will simply simulate a registration and update some property in the data object of the Vue instance.</p>
<p>We will place the following code inside our HTML file:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Register an account --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fab fa-twitter fa-lg fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Create your account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"registerAccount"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"25"</span> <span class="hljs-attr">required</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"25"</span> <span class="hljs-attr">required</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"16"</span> <span class="hljs-attr">required</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Let's break this down. First, the form tag has a <code>v-on</code> directive with a <code>submit</code> argument so it will listen for a submit event. It also has an event modifier <code>.prevent</code> so when we hit the submit button the page doesn't refresh. </p>
<p>Inside the <code>v-on</code> directive there is a method called <code>registerAccount</code> that we need to create inside the methods of the Vue instance.</p>
<p>Inside the form, we have the three input fields: name, email, and password with labels. We wrapped each field inside a div with a class of <code>form_group</code>. Later we can replicate the style of the Twitter registration fields and show a character counter. </p>
<p>Each input field has a <code>v-model</code> directive that binds the input to its data property. </p>
<h3 id="heading-how-to-simulate-a-registration-form-vue">How to simulate a registration form - Vue</h3>
<p>Let's move on to the Vue instance to make the binding between the form and the data object properties.</p>
<p>Here we also need a place where we can store the details that the user submits so we will create another property for that. </p>
<p>Looking at the input fields, we also put a <code>maxlength</code> property on them, which is 25 for the name and email and 16 for the password. </p>
<p>Like we did previously when we learned about the v-model, we can create a property for these limits so that we can use it to show the user how many characters the user has left. </p>
<p>The Vue instance will look like this:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">userData</span>: {}
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
        <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>
    },
    <span class="hljs-attr">methods</span>: {
        registerAccount(){
            <span class="hljs-comment">// record user details</span>
            <span class="hljs-comment">// add registration to localStorage</span>
            <span class="hljs-comment">// clear the registration fields</span>

        }
    }

});
</code></pre>
<p>Let's break this down. First inside the <code>data:{}</code> object, we defined an object to store and retrieve the <code>userData</code>. Then we added the properties <code>name</code>, <code>email</code>, and <code>password</code> to make the two-way data binding work. 
Finally we added the <code>max_length</code> and <code>max_pass_length</code> propeties.</p>
<h3 id="heading-how-to-show-input-character-counter">How to show input character counter</h3>
<p>OK, now that we have a binding between the input fields and our properties, we can show a character counter to the user while they're typing. </p>
<p>This is fairly simple – all there is to do is to show the length of each input property and compare it with the max length properties we have set in the Vue instance.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ name.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>So here we created a string using an in-template expression. We've shown the length of the <code>name</code> property and the value of the <code>max_length</code> so that while the user types we show something like this: 13/25. </p>
<p>We've also used a <code>v-bind</code> directive on the <code>maxlength</code> attribute so that its value is bound to the value of the property we defined in the Vue instance. So in case we want to change it we can do so in one place.</p>
<p>We will do the same for the other fields. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"registerAccount"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ name.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ email.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ password.length + '/' + max_pass_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_pass_length"</span> <span class="hljs-attr">required</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-add-the-logic-to-the-registeraccount-method">How to add the logic to the <code>registerAccount</code> method</h3>
<p>Now it's time to work on the form submission logic. We will simply populate the object stored in the property <code>userData</code> when the user submits the form. </p>
<p>Inside the <code>registerAccount</code> method we will add the details the user passes and build our object. </p>
<pre><code class="lang-js"> registerAccount(){
            <span class="hljs-comment">// record user details</span>
            <span class="hljs-built_in">this</span>.userData.name = <span class="hljs-built_in">this</span>.name,
            <span class="hljs-built_in">this</span>.userData.email = <span class="hljs-built_in">this</span>.email,
            <span class="hljs-built_in">this</span>.userData.password = <span class="hljs-built_in">this</span>.password

            <span class="hljs-comment">// add registration to localStorage</span>

            <span class="hljs-comment">// clear the registration fields</span>
            <span class="hljs-built_in">this</span>.name = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.email = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.password = <span class="hljs-string">""</span>;
        }
</code></pre>
<p>Here we have taken the value of the properties name, email, and password and assigned them to properties we created in the <code>userData</code> object.</p>
<p>This seems fine mostly because we have put on our input fields the <code>required</code> attribute – but if we remove it we will be able to submit an empty form, and we don't want that. </p>
<p>So let's add a very basic form of validation to at least check if the user has typed something inside our form, otherwise we show an error. </p>
<p>To do this, we need to add an if block inside the method and also an error property to the data object. Our file now looks like this:</p>
<pre><code class="lang-js">

<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">userData</span>: {},
        <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
        <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,

    },  
    <span class="hljs-attr">methods</span>: {
        registerAccount(){
            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.name !== <span class="hljs-string">""</span> &amp;&amp; <span class="hljs-built_in">this</span>.email !== <span class="hljs-string">""</span> &amp;&amp; <span class="hljs-built_in">this</span>.password !== <span class="hljs-string">""</span> ) 
            {
                <span class="hljs-built_in">this</span>.userData.id = ++<span class="hljs-built_in">this</span>.usersID,
                <span class="hljs-built_in">this</span>.userData.name = <span class="hljs-built_in">this</span>.name,
                <span class="hljs-built_in">this</span>.userData.email = <span class="hljs-built_in">this</span>.email,
                <span class="hljs-built_in">this</span>.userData.password = <span class="hljs-built_in">this</span>.password

            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">this</span>.error = <span class="hljs-string">"Complete all the form fields"</span>
            }

        <span class="hljs-comment">/* Add registration data to the local storage */</span>


        <span class="hljs-comment">/* Clear the registration inputs */</span>
        <span class="hljs-built_in">this</span>.name = <span class="hljs-string">""</span>;
        <span class="hljs-built_in">this</span>.email = <span class="hljs-string">""</span>;
        <span class="hljs-built_in">this</span>.password = <span class="hljs-string">""</span>;
        }

    }

});
</code></pre>
<p>Here in the <code>registerAccount</code> we've written a conditional that checks if the length of the name property is not empty, if the email property isn't empty, and if the password isn't empty  <code>this.name !== "" &amp;&amp; this.email !== "" &amp;&amp; this.password !== ""</code>. </p>
<p>If all these checks evaluate to a true value, then we run the code inside the block. Otherwise we run the code in the <code>else</code> block that updates the value of the <code>error</code> property that we will now use in our template to show the error message. </p>
<p>We also added a new property <code>usersID: 0,</code> that we used inside the if block to assign an id property to the <code>userData</code> object, just to make our application more realistic. But of course it is useless, as we will not have a database where we store all user details. We'll just store a single user inside their browser's local storage.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"registerAccount"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ name.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ email.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ password.length + '/' + max_pass_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_pass_length"</span> <span class="hljs-attr">required</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>


<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error.length &gt; 0"</span>&gt;</span> {{error}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now our form is complete and we're also displaying an error message to the user if the required attributes are removed from our markup. </p>
<p>But our data do not persist and when the page is refreshed –everything's all gone. Let's tackle that using the localStorage API.</p>
<p>Inside our Vue instance, we need to set an item in the local storage. But we also need to save the entire <code>userData</code> object so that later we can use its data to display a message to the registered user.</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Add registration data to the local storage */</span>
<span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered'</span>, <span class="hljs-literal">true</span>)
<span class="hljs-comment">/* Add the whole userData object as JSON string */</span>
<span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered_user'</span>, <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.userData))
</code></pre>
<p>Here we use the <code>setItem</code> method of the Local Storage API to add an item to the local storage so that later we can use it to check if the user is registered or not. </p>
<p>Then we also need to store the entire <code>userData</code> object as a string. To do that we use the <code>JSON.stringify</code> method that will turn the object into a JSON string that can be saved in the localStorage.</p>
<p>Our JS file is now as follows:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">userData</span>: {},
        <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
        <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,
    },  
    <span class="hljs-attr">methods</span>: {
        registerAccount(){
            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.name !== <span class="hljs-string">""</span>  &amp;&amp; <span class="hljs-built_in">this</span>.email !== <span class="hljs-string">""</span> &amp;&amp; <span class="hljs-built_in">this</span>.password !== <span class="hljs-string">""</span> ) {
                <span class="hljs-built_in">this</span>.userData.id = ++<span class="hljs-built_in">this</span>.usersID,
                <span class="hljs-built_in">this</span>.userData.name = <span class="hljs-built_in">this</span>.name,
                <span class="hljs-built_in">this</span>.userData.email = <span class="hljs-built_in">this</span>.email,
                <span class="hljs-built_in">this</span>.userData.password = <span class="hljs-built_in">this</span>.password

            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">this</span>.error = <span class="hljs-string">"Complete all the form fields"</span>
            }

        <span class="hljs-comment">/* Add registration data to the local storage */</span>
        <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered'</span>, <span class="hljs-literal">true</span>)
        <span class="hljs-comment">/* Add the whole userData object as JSON string */</span>
        <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered_user'</span>, <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.userData))


        <span class="hljs-comment">/* Clear the registration inputs */</span>
        <span class="hljs-built_in">this</span>.name = <span class="hljs-string">""</span>;
        <span class="hljs-built_in">this</span>.email = <span class="hljs-string">""</span>;
        <span class="hljs-built_in">this</span>.password = <span class="hljs-string">""</span>;
        }

    }

});
</code></pre>
<p>Now when the user visits our application page, we need to check inside the browser's local storage to see if there is a key called <code>simple_tweet_registered</code>. If there is, we can assume that the user is registered and we can show the next section, the tweet box. Otherwise, we show the registration form. </p>
<p>We will do that by creating a <code>registered: false</code> property in the data object and use it to display or hide the registration form.</p>
<pre><code class="lang-js">
<span class="hljs-attr">data</span>: {
    <span class="hljs-attr">userData</span>: {},
    <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
    <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
    <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">registered</span>: <span class="hljs-literal">false</span>,      
}
</code></pre>
<p>Wrap the form around a div with a directive <code>v-if="!registered"</code> like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!registered"</span>&gt;</span>
    // here goes the form
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span> Tweetbox <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Our final HTML file now looks like this:</p>
<pre><code class="lang-html">    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fab fa-twitter fa-lg fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Register an account --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!registered"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">form</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Create your account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"registerAccount"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ name.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ email.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ password.length + '/' + max_pass_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_pass_length"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>


            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error.length &gt; 0"</span>&gt;</span> {{error}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Add tweet --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetBox"</span> <span class="hljs-attr">v-else</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome username_here write your first Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now to make this work, we will use the lifecycle hook we created which lets us inject our code when the Vue instance has been created. This is because we want to check this before mounting our root element. </p>
<p>So let's add a life cycle hook to the Vue instance. We will check if our key is there, and if so we will update the value of the <code>registered</code> property to <code>true</code>. </p>
<p>We have also stored the full <code>userData</code> object in the local Storage so we can use it to repopulate the <code>userData</code> object when the page is refreshed with the details the user submitted.</p>
<pre><code class="lang-js">created(){
    <span class="hljs-comment">/* Check if the user is registered and set the registered to true */</span>
    <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"simple_tweet_registered"</span>) === <span class="hljs-string">'true'</span>){
        <span class="hljs-built_in">this</span>.registered = <span class="hljs-literal">true</span>;
    }
    <span class="hljs-comment">// repopulate the userData object</span>
     <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>)) {
            <span class="hljs-built_in">this</span>.userData = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>))
        }

}
</code></pre>
<p>To turn a JSON string back into an object, we can use the <code>JSON.parse</code> method.</p>
<p>Now it's all set for the next task – show a tweet form to the user after registration.</p>
<p>Our code so far looks like this:</p>
<p>The main.js file:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">userData</span>: {},
        <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
        <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">registered</span>: <span class="hljs-literal">false</span>,
    },

    <span class="hljs-attr">methods</span>: {
          registerAccount(){

              <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.name.length &gt; <span class="hljs-number">0</span> &amp;&amp; <span class="hljs-built_in">this</span>.name.length &lt;= <span class="hljs-built_in">this</span>.max_length &amp;&amp; <span class="hljs-built_in">this</span>.email !== <span class="hljs-string">""</span> &amp;&amp; <span class="hljs-built_in">this</span>.password !== <span class="hljs-string">""</span> ) {

                    <span class="hljs-built_in">this</span>.userData.id = ++<span class="hljs-built_in">this</span>.usersID,
                    <span class="hljs-built_in">this</span>.userData.name = <span class="hljs-built_in">this</span>.name,
                    <span class="hljs-built_in">this</span>.userData.email = <span class="hljs-built_in">this</span>.email,
                    <span class="hljs-built_in">this</span>.userData.password = <span class="hljs-built_in">this</span>.password
                    <span class="hljs-built_in">this</span>.registered=<span class="hljs-literal">true</span>;



              } <span class="hljs-keyword">else</span> {
                  <span class="hljs-built_in">this</span>.error = <span class="hljs-string">"Complete all the form fields"</span>
              }

            <span class="hljs-comment">/* Add registration data to the local storage */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered'</span>, <span class="hljs-literal">true</span>)
            <span class="hljs-comment">/* Add the whole userData object as JSON string */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered_user'</span>, <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.userData))

            <span class="hljs-comment">/* Clear the registration inputs */</span>
            <span class="hljs-built_in">this</span>.name = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.email = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.password = <span class="hljs-string">""</span>;
        }

    },
    created(){
        <span class="hljs-comment">/* Check if the user is registered and set the registered to true */</span>
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"simple_tweet_registered"</span>) === <span class="hljs-string">'true'</span>){
            <span class="hljs-built_in">this</span>.registered = <span class="hljs-literal">true</span>;
        }
        <span class="hljs-comment">// repopulate the userData object</span>
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>)) {
            <span class="hljs-built_in">this</span>.userData = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>))
        }

    }

});
</code></pre>
<p>And the HTML inside the <code>app</code> element:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fab fa-twitter fa-lg fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Register an account --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!registered"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">form</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Create your account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"registerAccount"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ name.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ email.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ password.length + '/' + max_pass_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_pass_length"</span> <span class="hljs-attr">required</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>


        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error.length &gt; 0"</span>&gt;</span> {{error}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Add tweet --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetBox"</span> <span class="hljs-attr">v-else</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome {{ userData.name }} write your first Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here in the HTML, since we used the <code>v-else</code> on the add tweet section and used the local storage to retrieve the data submitted by the user, we can use an in-template expression to grab the user name so that we can output a welcome message. </p>
<p>In the next section, we will create a tweet box form so that after the registration the user can write a tweet.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/v1j_bDDd6jI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-how-to-create-a-tweet-box-form-html">How to create a tweet box form - HTML</h3>
<p>Now it's time to build our add tweet form. We did something very similar earlier in this article, but now we will need to store and make the data persistent. This lets us show a list of tweets even when the page refreshes.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetBox"</span> <span class="hljs-attr">v-else</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome {{ userData.name }} write your first Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"sendTweet"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tweet"</span>&gt;</span>
                Send your tweet
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ tweetMsg.length + '/' + max_tweet }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweetMsg"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"200"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This is nothing new to us now. Inside the <code>tweetBox</code> element we add a form with the usual v-on directive and a method  <code>sendTweet</code> that we will need to define inside the methods object. This will take the tweet and save it somewhere, maybe in a property in the data object.</p>
<p>Inside the form, there is a <code>textarea</code> that has a <code>v-model</code> directive that binds it to a <code>tweetMsg</code> property that we need to create.</p>
<p>Finally, a submit button.</p>
<p>We also have a span inside the tweet label that shows a character counter to the user as we did before in the registration form. </p>
<p>Here we have a new property <code>max_tweet</code> that is used to show the limit and the <code>tweetMsg.length</code> is used to show the current number of the characters inserted.</p>
<p>You can watch the video on <a target="_blank" href="https://youtu.be/xFwfrIciFt0">YouTube here</a> if you want to review what you've learned.</p>
<h3 id="heading-create-a-tweets-box-form-vue">Create a tweets box form - Vue</h3>
<p>Let's go to the Vue instance and add the properties and the <code>sendTweet</code> methods.</p>
<p>Our data object now has three more properties, the <code>max_tweet</code> set to <code>200</code>, the <code>tweetMsg</code> that binds to the <code>textarea</code>, and a <code>tweets</code> array that we will use to store all tweets the user sends.</p>
<pre><code class="lang-js">data: {
    <span class="hljs-attr">userData</span>: {},
    <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
    <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
    <span class="hljs-attr">max_tweet</span>: <span class="hljs-number">200</span>, <span class="hljs-comment">// max tweets lenght</span>
    <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">registered</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">tweetMsg</span>: <span class="hljs-string">""</span>, <span class="hljs-comment">// current tweet</span>
    <span class="hljs-attr">tweets</span>: [] <span class="hljs-comment">// list of tweets</span>
}
</code></pre>
<p>Inside the methods, we have a new method that will be invoked by the v-on directive when the form is submitted:</p>
<pre><code class="lang-js">
sendTweet(){
    <span class="hljs-comment">/* Store the tweet in the tweets property */</span>
    <span class="hljs-built_in">this</span>.tweets.unshift(
        {
            <span class="hljs-attr">text</span>: <span class="hljs-built_in">this</span>.tweetMsg,
            <span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleTimeString()
        }

    );
    <span class="hljs-comment">/* Empty the tweetMsg property */</span>
    <span class="hljs-built_in">this</span>.tweetMsg = <span class="hljs-string">""</span>;
    <span class="hljs-comment">//console.log(this.tweets);</span>

    <span class="hljs-comment">/* Tranform the object into a string  */</span>
    stringTweets = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.tweets)
    <span class="hljs-comment">//console.log(stringTweets);</span>

    <span class="hljs-comment">/* Add to the local storage the stringified tweet object */</span>
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_tweets'</span>, stringTweets)
},
</code></pre>
<p>The code above does four things:</p>
<ul>
<li>takes the tweets array and adds in it an object to represent a single tweet with text and date properties. To the text property, we assign the value of the <code>tweetMsg</code> that is bound with the <code>textarea</code>. For the date, we create a new date object with the <code>new Date().toLocaleTimeString()</code> method.</li>
<li>we empty the value of the <code>tweetMsg</code></li>
<li>we transform the tweets property into a string using the method <code>JSON.stringify(this.tweets)</code> </li>
<li>Then we add it to the local storage.</li>
</ul>
<p>Our final main.js file now looks like this:</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">userData</span>: {},
        <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
        <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">registered</span>: <span class="hljs-literal">false</span>,
    },

    <span class="hljs-attr">methods</span>: {
          registerAccount(){

              <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.name.length &gt; <span class="hljs-number">0</span> &amp;&amp; <span class="hljs-built_in">this</span>.name.length &lt;= <span class="hljs-built_in">this</span>.max_length &amp;&amp; <span class="hljs-built_in">this</span>.email !== <span class="hljs-string">""</span> &amp;&amp; <span class="hljs-built_in">this</span>.password !== <span class="hljs-string">""</span> ) {

                    <span class="hljs-built_in">this</span>.userData.id = ++<span class="hljs-built_in">this</span>.usersID,
                    <span class="hljs-built_in">this</span>.userData.name = <span class="hljs-built_in">this</span>.name,
                    <span class="hljs-built_in">this</span>.userData.email = <span class="hljs-built_in">this</span>.email,
                    <span class="hljs-built_in">this</span>.userData.password = <span class="hljs-built_in">this</span>.password
                    <span class="hljs-built_in">this</span>.registered=<span class="hljs-literal">true</span>;



              } <span class="hljs-keyword">else</span> {
                  <span class="hljs-built_in">this</span>.error = <span class="hljs-string">"Complete all the form fields"</span>
              }

            <span class="hljs-comment">/* Add registration data to the local storage */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered'</span>, <span class="hljs-literal">true</span>)
            <span class="hljs-comment">/* Add the whole userData object as JSON string */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered_user'</span>, <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.userData))

            <span class="hljs-comment">/* Clear the registration inputs */</span>
            <span class="hljs-built_in">this</span>.name = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.email = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.password = <span class="hljs-string">""</span>;
        },
        sendTweet(){
            <span class="hljs-comment">/* Store the tweet in the tweets property */</span>
            <span class="hljs-built_in">this</span>.tweets.unshift(
                {
                    <span class="hljs-attr">text</span>: <span class="hljs-built_in">this</span>.tweetMsg,
                    <span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleTimeString()
                }

            );
            <span class="hljs-comment">/* Empty the tweetMsg property */</span>
            <span class="hljs-built_in">this</span>.tweetMsg = <span class="hljs-string">""</span>;
            <span class="hljs-comment">//console.log(this.tweets);</span>

            <span class="hljs-comment">/* Tranform the object into a string  */</span>
            stringTweets = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.tweets)
            <span class="hljs-comment">//console.log(stringTweets);</span>

            <span class="hljs-comment">/* Add to the local storage the stringified tweet object */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_tweets'</span>, stringTweets)
        },


    },
    created(){
        <span class="hljs-comment">/* Check if the user is registered and set the registered to true */</span>
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"simple_tweet_registered"</span>) === <span class="hljs-string">'true'</span>){
            <span class="hljs-built_in">this</span>.registered = <span class="hljs-literal">true</span>;
        }
        <span class="hljs-comment">// repopulate the userData object</span>
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>)) {
            <span class="hljs-built_in">this</span>.userData = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>))
        }

    }

});
</code></pre>
<p>Now that we've completed this part, we can show a list of tweets and also handle when the page is refreshed, and the local storage has in it our tweets object. We will need to parse it back and add its content to the <code>tweets</code> property to see the list.</p>
<p>Next, we will learn how to show the list of tweets using a v-for directive.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/xFwfrIciFt0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-how-to-show-a-list-of-tweets-html">How to show a list of tweets - HTML</h3>
<p>Inside our root element, add the following code:</p>
<pre><code class="lang-html"> <span class="hljs-comment">&lt;!-- Show all tweets --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card_tweets"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweets"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweets.length &gt; 0"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Tweets<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetMsg"</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(tweet, index) in tweets"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                    {{tweet.text}}
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetDate"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-calendar-alt fa-sm fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>{{tweet.date}}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>No tweets to show<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here we wrap everything in a div with a class <code>card_tweets</code>. Then we use a v-if directive inside a child section to check if there are tweets in the <code>tweets</code> array <code>v-if="tweets.length &gt; 0"</code>. </p>
<p>Inside this section, we can loop over the tweets array using a <code>v-for="(tweet, index) in tweets"</code> directive. After that we use in-template expressions to show the tweet text property <code>{{tweet.text}}</code> and the data <code>{{tweet.date}}</code>.</p>
<p>After the <code>section</code> we can use a <code>v-else</code> directive to show a message in case there are no tweets stored inside the tweets array <code>&lt;div v-else&gt;No tweets to show&lt;/div&gt;</code>. Done. </p>
<p>Now there's one last thing we need to do, and that is to figure out what to do to remove tweets from the list.</p>
<p>But when the user refreshes the page, everything is gone. So we need to work with the <code>localStorage</code> once again to repopulate our tweets array from it before rendering the root element.</p>
<p>Inside the <code>created</code> lifecycle hook we will now write some code to parse the tweets and save them back in the <code>tweets</code> property:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Parse all tweets from the local storage  */</span>
<span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"simple_tweet_tweets"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"There is a list of tweets"</span>);
    <span class="hljs-built_in">this</span>.tweets = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_tweets'</span>))
}<span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No tweets here"</span>);
}
</code></pre>
<p>Here we used the <code>localStorage</code> API to first check if there was a key called <code>simple_tweet_tweets</code>. If so, we grab the tweets property using <code>this.tweets</code> and assign to it the content of the <code>localStorage</code>. But we parse the string back to <code>JSON</code> with <code>JSON.parse</code> so we write <code>this.tweets = JSON.parse(localStorage.getItem('simple_tweet_tweets'))</code>.</p>
<p>Now everything works. After we refresh the page, the tweets are still there. Let's move on. In the next step, we will add a method to remove tweets from the list.</p>
<p>You can watch the video on <a target="_blank" href="https://youtu.be/3DzBkUHH3bU">YouTube here</a> or at the end of this section to review what you've learned.</p>
<h3 id="heading-how-to-remove-tweets">How to remove tweets</h3>
<p>Inside the div that contains the tweet message, we can add another div to show a link and a trash icon. This lets the user click it and remove that tweet. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweet_remove"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"removeTweet(index)"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"remove"</span>&gt;</span>Delete this tweet <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-trash fa-xs fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here we simply used a v-on short syntax directive on the div and invoked a method <code>removeTweet(index)</code>, passing to the method the element index so that we know what to remove.</p>
<p>Let's build our <code>removeTweet</code> method now:</p>
<pre><code class="lang-js">removeTweet(index){
    <span class="hljs-keyword">let</span> removeIt = confirm(<span class="hljs-string">"Are you sure you want to remove this tweet?"</span>)
    <span class="hljs-keyword">if</span>(removeIt) {
        <span class="hljs-built_in">this</span>.tweets.splice(index, <span class="hljs-number">1</span>);
        <span class="hljs-comment">/* Remove the item also from the local storage */</span>
        <span class="hljs-built_in">localStorage</span>.simple_tweet_tweets = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.tweets)
    }
}
</code></pre>
<p>This bit of code is pretty straightforward. Our method accepts an index that represents the position of the tweet object in the array obtained from the v-for directive when the method is invoked. </p>
<p>We then create a variable to ask the user to confirm that they want to delete the tweet. We used the <code>confirm</code> function for that. </p>
<p>If the value of the <code>removeIt</code> variable is true, then we execute the code and use <code>this.tweets.splice(index, 1)</code> to remove the tweet from the array using its index. </p>
<p>Finally we update the <code>localStorage</code> value by assigning to is the new array using the <code>localStorage.simple_tweet_tweets = JSON.stringify(this.tweets)</code>.</p>
<h3 id="heading-final-code">Final Code</h3>
<p>Our code is now complete. You can find the final code below or inside the repository here: [https://bitbucket.org/fbhood/simple-tweet-app/src/master/].</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Vue 2 Hello World<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://use.fontawesome.com/releases/v5.1.1/css/all.css"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Axios CDN --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.0/axios.min.js"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha512-DZqqY3PiOvTP9HkjIWgjO6ouCbq+dxqWoJZ/Q+zPYNHmlnI2dQnbJ5bxAHpAMw+LXRm4D72EIRXzvcHQtE8/VQ=="</span>
        <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- development version, includes helpful console warnings --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://use.fontawesome.com/releases/v5.1.1/css/all.css"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fab fa-twitter fa-lg fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Register an account --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!registered"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">form</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Create your account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"register"</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"registerAccount"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>Name
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ name.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ email.length + '/' + max_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_length"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ password.length + '/' + max_pass_length }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:maxlength</span>=<span class="hljs-string">"max_pass_length"</span> <span class="hljs-attr">required</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>


            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error.length &gt; 0"</span>&gt;</span> {{error}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Add tweet --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetBox"</span> <span class="hljs-attr">v-else</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome {{ userData.name }} write your first Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"sendTweet"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tweet"</span>&gt;</span>
                        Send your tweet
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {{ tweetMsg.length + '/' + max_tweet }}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"tweetMsg"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"200"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Tweet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Show all tweets --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card_tweets"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweets"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweets.length &gt; 0"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Tweets<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetMsg"</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(tweet, index) in tweets"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                    {{tweet.text}}
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweetDate"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-calendar-alt fa-sm fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>{{tweet.date}}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweet_remove"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"removeTweet(index)"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"remove"</span>&gt;</span>Delete this tweet <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-trash fa-xs fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>No tweets to show<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>JavaScript file</p>
<pre><code class="lang-js">
<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">userData</span>: {},
        <span class="hljs-attr">usersID</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">password</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">max_length</span>: <span class="hljs-number">25</span>,
        <span class="hljs-attr">max_pass_length</span>: <span class="hljs-number">16</span>,
        <span class="hljs-attr">max_tweet</span>: <span class="hljs-number">200</span>,
        <span class="hljs-attr">error</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">registered</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">tweetMsg</span>: <span class="hljs-string">""</span>,
        <span class="hljs-attr">tweets</span>: []
    },

    <span class="hljs-attr">methods</span>: {
          registerAccount(){

              <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.name.length &gt; <span class="hljs-number">0</span> &amp;&amp; <span class="hljs-built_in">this</span>.name.length &lt;= <span class="hljs-built_in">this</span>.max_length &amp;&amp; <span class="hljs-built_in">this</span>.email !== <span class="hljs-string">""</span> &amp;&amp; <span class="hljs-built_in">this</span>.password !== <span class="hljs-string">""</span> ) {

                    <span class="hljs-built_in">this</span>.userData.id = ++<span class="hljs-built_in">this</span>.usersID,
                    <span class="hljs-built_in">this</span>.userData.name = <span class="hljs-built_in">this</span>.name,
                    <span class="hljs-built_in">this</span>.userData.email = <span class="hljs-built_in">this</span>.email,
                    <span class="hljs-built_in">this</span>.userData.password = <span class="hljs-built_in">this</span>.password
                    <span class="hljs-built_in">this</span>.registered=<span class="hljs-literal">true</span>;



              } <span class="hljs-keyword">else</span> {
                  <span class="hljs-built_in">this</span>.error = <span class="hljs-string">"Complete all the form fields"</span>
              }

            <span class="hljs-comment">/* Add registration data to the local storage */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered'</span>, <span class="hljs-literal">true</span>)
            <span class="hljs-comment">/* Add the whole userData object as JSON string */</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_registered_user'</span>, <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.userData))

            <span class="hljs-comment">/* Clear the registration inputs */</span>
            <span class="hljs-built_in">this</span>.name = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.email = <span class="hljs-string">""</span>;
            <span class="hljs-built_in">this</span>.password = <span class="hljs-string">""</span>;
        }, 
        sendTweet(){
            <span class="hljs-built_in">this</span>.tweets.unshift(
                {
                    <span class="hljs-attr">text</span>: <span class="hljs-built_in">this</span>.tweetMsg,
                    <span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleTimeString()
                }

            );
            <span class="hljs-built_in">this</span>.tweetMsg = <span class="hljs-string">""</span>;

            <span class="hljs-comment">//console.log(this.tweets);</span>
            stringTweets = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.tweets)
            <span class="hljs-comment">//console.log(stringTweets);</span>
            <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'simple_tweet_tweets'</span>, stringTweets)
        },
        removeTweet(index){
            <span class="hljs-keyword">let</span> removeIt = confirm(<span class="hljs-string">"Are you sure you want to remove this tweet?"</span>)
            <span class="hljs-keyword">if</span>(removeIt) {
                <span class="hljs-built_in">this</span>.tweets.splice(index, <span class="hljs-number">1</span>);
                <span class="hljs-comment">/* Remove the item also from the local storage */</span>
                <span class="hljs-built_in">localStorage</span>.simple_tweet_tweets = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">this</span>.tweets)
            }
        }
    },
    created(){
        <span class="hljs-comment">/* Check if the user is registered and set the registered to true */</span>
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"simple_tweet_registered"</span>) === <span class="hljs-string">'true'</span>){
            <span class="hljs-built_in">this</span>.registered = <span class="hljs-literal">true</span>;
        }

        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>)) {
            <span class="hljs-built_in">this</span>.userData = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_registered_user'</span>))
        }
        <span class="hljs-comment">/* Parse all tweets from the local storage  */</span>
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"simple_tweet_tweets"</span>)) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"There is a list of tweets"</span>);
            <span class="hljs-built_in">this</span>.tweets = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'simple_tweet_tweets'</span>))

        }<span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No tweets here"</span>);
        }
    }

});
</code></pre>
<p>We are ready to move forward with our Vue journey. Now it's time to learn about components.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/3DzBkUHH3bU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-vue-component-basics">Vue Component Basics</h2>
<p>A component is a reusable block of code that represents a specific element on the page.</p>
<p>Every web page and web or mobile application can be divided into components. Starting from the main sections we can further divide these into smaller bits and make sub-components. </p>
<p>Every component is reusable and is made of dedicated HTML, CSS, and JavaScript code. </p>
<p>We can use components to organize our code and build complex layouts that are easily maintainable.</p>
<p>Looking at a simple web page, it is usually made of a header, the main content area, and a footer. But each of these three pieces can be sub-divided into smaller parts. </p>
<p>For instance, a header can have the main navigation menu, a secondary menu, and a hero image. The same is true for the main and footer areas.</p>
<p>You can watch the video on <a target="_blank" href="https://youtu.be/wrqjPka7puo">YouTube here</a> or at the end of this section to review. You can also view the repository <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/12-components-basics/">here</a>.</p>
<p>To get started with components, we first need to learn how to register them, pass them data, and then we need to learn how to use them. Here are some great overviews of these topics to get you started:</p>
<ul>
<li>Register a component (https://vuejs.org/v2/guide/components-registration.html)</li>
<li>How to use Props (https://vuejs.org/v2/guide/components-props.html)</li>
<li>How to use Slots (https://vuejs.org/v2/guide/components-slots.html)</li>
<li>How the Data object works inside a component   </li>
<li>Child Component Events (https://vuejs.org/v2/guide/components-custom-events.html)</li>
<li>Dynamic Components ( https://vuejs.org/v2/guide/components-dynamic-async.html)</li>
</ul>
<h3 id="heading-how-to-register-a-component-in-vue">How to register a component in Vue</h3>
<p>To register a component, we need to use the <code>component</code> method on the <code>Vue()</code> object. After calling this function we need to define a template property with some markup specific to the component. </p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'component-name'</span>, {
    <span class="hljs-comment">// component properies here</span>
});
</code></pre>
<p>Every component needs to have a template property at least – without it a component doesn't make much sense.</p>
<p>So the next step is to define a template property and pass to it a string literal with some HTML tag:</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'test-component'</span>, {
    <span class="hljs-comment">// component properies here</span>
    <span class="hljs-attr">template</span>: <span class="hljs-string">`&lt;p&gt;I am a component&lt;/p&gt;`</span>

});
</code></pre>
<p>Now we can use our component multiple times inside our main HTML file by using its name as it was a standard HTML tag.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">test-component</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">test-component</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>However, our component will always render the same content, <code>I am a component</code>. Let's make it more useful and, following our tweets example, build a tweet message component.</p>
<pre><code class="lang-js">
Vue.component(<span class="hljs-string">'tweet-message'</span>, {

    <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div&gt;
           &lt;p&gt; Tweet text goes here &lt;/p&gt;
           &lt;p&gt; Date of the tweet goes here&lt;/p&gt;
       &lt;/div&gt;
    `</span>
});
</code></pre>
<p>OK, now that we have the base for our component we need to actually pass data to it.</p>
<p>One thing to notice here is that every component requires a single root element inside the template property. So, since we have two paragraphs, we wrapped them inside a div that will be considered the root element of our component. </p>
<p>Inside it, we can put whatever we want to build our custom component.</p>
<p>Let's move on to the next step and pass some data to the component.</p>
<h3 id="heading-how-to-use-props-in-vue">How to use props in Vue</h3>
<p>Now, given what we've learned so far, we want to pass data to our component as we did previously to bind data between the Vue instance and the markup file via the moustache syntax. </p>
<p>However, with components things work a bit differently. We use props to create a binding between our component and its template.</p>
<p>The <code>props</code> property can be defined as an array or as an object. 
When used as an array, we can specify the properties as strings inside the array and these can later be used inside the component like we usually do. </p>
<p>When we use an object we can pass the prop as the key and its type as the value. That will help to make sure that the exact data type is passed to our component. </p>
<p>Let's see an example of that.</p>
<p>Example of props as an Array:</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>, {
    <span class="hljs-attr">props</span>: [<span class="hljs-string">'text'</span>, <span class="hljs-string">'date'</span>]
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div&gt;
           &lt;p&gt; {{text}} &lt;/p&gt;
           &lt;p&gt; {{date}}&lt;/p&gt;
       &lt;/div&gt;
    `</span>
});
</code></pre>
<p>Use props as an object where the key is the property and the value is its type:</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>, {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">text</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">date</span>: <span class="hljs-built_in">String</span>
    }
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div&gt;
           &lt;p&gt; {{text}} &lt;/p&gt;
           &lt;p&gt; {{date}}&lt;/p&gt;
       &lt;/div&gt;
    `</span>
});
</code></pre>
<p>Once we have defined our properties, we can use them as HTML attributes and pass them the data we want our component to render onto the page. </p>
<p>For instance, we can use the component above to show a bunch of tweets using our newly created component.</p>
<pre><code class="lang-html">    <span class="hljs-comment">&lt;!-- Manually pass the data to the tweet message component --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is a component"</span> <span class="hljs-attr">date</span>=<span class="hljs-string">"25/12/2020"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This another component"</span> <span class="hljs-attr">date</span>=<span class="hljs-string">"26/12/2020"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This another component"</span> <span class="hljs-attr">date</span>=<span class="hljs-string">"27/12/2020"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Pass a javascript expression to the date property of the tweet message component --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This another component"</span> <span class="hljs-attr">:date</span>=<span class="hljs-string">"new Date().toLocaleString()"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
</code></pre>
<p>The first examples will render the string we passed between quotes. But 
to render the computed result of the new <code>Date()</code> instance we will need to use the v-bind directive so that its content is interpreted as JavaScript code.</p>
<p>You can review all this in the docs here: [https://vuejs.org/v2/guide/components-props.html].</p>
<h3 id="heading-the-data-property-inside-components">The data property inside components</h3>
<p>So far we have seen that we can bind data by defining properties inside the <code>data</code> object on a Vue instance. </p>
<p>When working with components the data object is not available as an object but as a function. This function can return an object with properties. This will make each component's instance unique and independent from the others.</p>
<p>Following our previous example, let's add a couple of CSS classes to our component.</p>
<p>First, we will edit our component template and bind the class attribute to a data property. Then we will create our data object.</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>, {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">text</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">date</span>: <span class="hljs-built_in">String</span>
    }
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div :class="tweetBoxWrapper"&gt;
           &lt;p&gt; {{text}} &lt;/p&gt;
           &lt;p :class="dateClass"&gt; {{date}}&lt;/p&gt;
       &lt;/div&gt;
    `</span>
});
</code></pre>
<p>Now our template will look for two data properties, <code>tweetBoxWrapper</code> and <code>dateClass</code>, that we can later use inside our CSS to add some style to our elements. Let's add the data function now.</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>, {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">text</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">date</span>: <span class="hljs-built_in">String</span>
    }
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div :class="tweetBoxWrapper"&gt;
           &lt;p&gt; {{text}} &lt;/p&gt;
           &lt;p :class="dateClass"&gt; {{date}}&lt;/p&gt;
       &lt;/div&gt;
    `</span>,
    data(){
        <span class="hljs-keyword">return</span> {
            <span class="hljs-comment">// Data properties go here</span>
            <span class="hljs-attr">tweetBoxWrapper</span>: <span class="hljs-string">"tweet-message"</span>,
            <span class="hljs-attr">dateClass</span>: <span class="hljs-string">"tweet-date"</span>,
        }
    }
});
</code></pre>
<p>Another thing we can do is to define a data property and use it inside our template, for instance, to dynamically show the current date. We can define a <code>now</code> property and use it in the template like we previously did with the <code>date</code> property:</p>
<pre><code class="lang-js">
Vue.component(<span class="hljs-string">'tweet-message'</span>, {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-string">'text'</span>: <span class="hljs-built_in">String</span>,

    },
     <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div :class="tweetBoxWrapper"&gt;
           &lt;p&gt; {{text}} &lt;/p&gt;
           &lt;p :class="dateClass"&gt;{{now}}&lt;/p&gt;

       &lt;/div&gt;

    `</span>,
    data(){
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">tweetBoxWrapper</span>: <span class="hljs-string">"tweet-message"</span>,
            <span class="hljs-attr">dateClass</span>: <span class="hljs-string">"tweet-date"</span>,
            <span class="hljs-attr">now</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toDateString(), <span class="hljs-comment">// 3 </span>

        }
    }


});
</code></pre>
<p>In the example above we have used both <code>props</code> and <code>data</code>. We can use the prop <code>text</code> as an attribute when we use our component <code>&lt;tweet-message text="This is a component"&gt;&lt;/tweet-message&gt;</code>. The properties we returned in the <code>data</code> method are bound to the template and will render the information we specify right there in the data method.</p>
<p>When inside the data method, we need to remember that props defined here are accessible using the <code>this</code> keyword.</p>
<p>So if we want to store the value of the text prop inside a property in the data object, we can grab it like this:</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>, {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-string">'text'</span>: <span class="hljs-built_in">String</span>,

    },
     <span class="hljs-attr">template</span>: <span class="hljs-string">`
       &lt;div :class="tweetBoxWrapper"&gt;
           &lt;p&gt; {{text}} &lt;/p&gt;
           &lt;p :class="dateClass"&gt;{{now}}&lt;/p&gt;

       &lt;/div&gt;

    `</span>,
    data(){
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">tweetBoxWrapper</span>: <span class="hljs-string">"tweet-message"</span>,
            <span class="hljs-attr">dateClass</span>: <span class="hljs-string">"tweet-date"</span>,
            <span class="hljs-attr">now</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toDateString(), 
            <span class="hljs-attr">message</span>: <span class="hljs-built_in">this</span>.text
        }
    }


});
</code></pre>
<p>Next, we will learn about slots.</p>
<h3 id="heading-how-to-use-slots">How to use slots</h3>
<p>There are situations when we just don't know or want to strictly define what goes inside a component. Or we might want to let the user decide its content when they use our component.</p>
<p>In such cases, we can use slots when we declare the template of our component.</p>
<p>Let's imagine that we have another component that we want to use to divide tweets into different sections.</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-section'</span>, {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-string">'title'</span>: <span class="hljs-built_in">String</span>,

    },
     <span class="hljs-attr">template</span>: <span class="hljs-string">`
        &lt;div class="tweet_section"&gt;
            &lt;h2&gt;{{title}}&lt;/h2&gt;
           &lt;slot&gt;&lt;/slot&gt;
       &lt;/div&gt;  
    `</span>    
});
</code></pre>
<p>Our new component can be as simple as that, a div with a class <code>tweet_section</code>, an <code>h2</code> that binds to a prop, and a slot. The slot means that inside our component we can put whatever we want, like nesting other elements and even other components.</p>
<pre><code class="lang-html">
<span class="hljs-tag">&lt;<span class="hljs-name">tweet-section</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Latest Tweets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is my first tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is my second tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is my third tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is my fourth tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">tweet-section</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">tweet-section</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Most popular"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Trendy in IT<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is a very popular tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"This is another popular tweet"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tweet-section</span>&gt;</span>
</code></pre>
<p>We've barely scratched the surface here, but with what we know we can already modify our <code>simple_twitter</code> application to use components. Along the way, we will also learn how events work inside components.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/wrqjPka7puo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-update-your-simpletwitter-project-with-components">How to Update Your Simple_twitter Project with Components</h2>
<p>Now that we have a basic understanding of components, we can update the simple Twitter project we built in the previous videos and use components to make our code better.</p>
<p>We need to do a few things to make this happen, and create a component:</p>
<ol>
<li>We need to decide what component we want to build </li>
<li>We need to extract the code from the markup and place it in the template property</li>
<li>We need to refactor our code to make the component work.</li>
</ol>
<p>You can watch the tutorial on <a target="_blank" href="https://youtu.be/HanHyGFC6Sc">YouTube here</a>
or checkout the repository <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/13-simple-twitter-components/">here</a>.</p>
<p>Let's say we want to create a component for the tweet message. </p>
<h3 id="heading-how-to-create-the-component">How to create the component</h3>
<p>Let's create a component for a tweet message like this:</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>,{
    <span class="hljs-attr">template</span>: <span class="hljs-string">``</span>
});
</code></pre>
<h3 id="heading-how-to-move-the-tweetmsg-element">How to move the tweetMsg element</h3>
<p>Then we have to move the <code>tweetMsg</code> element inside the  <code>template</code> property of our component:</p>
<pre><code class="lang-js">
Vue.component(<span class="hljs-string">'tweet-message'</span>,{
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;div class="tweetMsg" v-for="(tweet, index) in tweets"&gt;
        &lt;p&gt;
            {{ tweet.text}}
        &lt;/p&gt;
        &lt;div class="tweetDate"&gt;
            &lt;i class="fas fa-calendar fa-sm fa-fw"&gt;&lt;/i&gt;{{ tweet.date }}
        &lt;/div&gt;
        &lt;div class="tweet_remove" @click="removeTweet(index)"&gt;
            &lt;span class="remove"&gt;Delete this tweet &lt;i class="fas fa-trash fa-sm fa-fw"&gt;&lt;/i&gt;&lt;/span&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    `</span>
});
</code></pre>
<p>After that, we need to update the template because the v-for directive now is useless. So we will remove it and add it back later when we are ready to use the component.</p>
<p>Given that we will not have a v-for directive at this point, we still want to use the tweet variable to grab the tweet, so we will pass it as a <code>props</code>.</p>
<pre><code class="lang-js">Vue.component(<span class="hljs-string">'tweet-message'</span>,{
    <span class="hljs-attr">props</span>: {
        <span class="hljs-string">'tweet'</span>: <span class="hljs-built_in">Object</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;div class="tweetMsg"&gt;
        &lt;p&gt;
            {{ tweet.text}}
        &lt;/p&gt;
        &lt;div class="tweetDate"&gt;
            &lt;i class="fas fa-calendar fa-sm fa-fw"&gt;&lt;/i&gt;{{ tweet.date }}
        &lt;/div&gt;
        &lt;div class="tweet_remove" @click="removeTweet(index)"&gt;
            &lt;span class="remove"&gt;Delete this tweet &lt;i class="fas fa-trash fa-sm fa-fw"&gt;&lt;/i&gt;&lt;/span&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    `</span>
});
</code></pre>
<h3 id="heading-how-to-emit-a-custom-event">How to emit a custom event</h3>
<p>There is also an event listener that needs to change to let our application work as expected. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweet_remove"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"removeTweet(index)"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"remove"</span>&gt;</span>Delete this tweet <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-trash fa-sm fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The code here <code>&lt;div class="tweet_remove" @click="removeTweet(index)"&gt;</code> listens to click events so the user can remove a tweet by clicking on it. </p>
<p>This will need to go, and we need to replace it with a special method of the Vue instance called <code>$emit()</code>. Our component instance will need to communicate with the parent instance and tell it that it wants to trigger the remove tweet method.  </p>
<p>To solve this problem, Vue provides a custom events system. It allows us to use the v-on directive to listen not only to native DOM events but also to custom events defined at the component level.</p>
<p>We need to update this line of code: </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweet_remove"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"removeTweet(index)"</span>&gt;</span>
</code></pre>
<p>and change it like so: </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweet_remove"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"$emit('remove-tweet', 'index')"</span>&gt;</span>
</code></pre>
<p>Let's break this down: we keep using the v-on directive in its short form <code>@</code>. Then we use the Vue <code>$emit</code> method to define a custom event that our component will emit when we click on this element. </p>
<p>To the <code>$emit</code> method we pass two parameters, the first is the name of the custom event <code>remove-tweet</code>, and the second is a parameter that we want to pass to the event listener when we use <code>index</code>. That will be the index of the element we want to delete. </p>
<p>So that the parent instance can listen to our event, trigger the <code>removeTweet</code> method we defined in the main Vue instance and remove the correct tweet.</p>
<h3 id="heading-put-it-all-together-1">Put it all together</h3>
<p>Our final component now looks like this:</p>
<pre><code class="lang-js">
Vue.component(<span class="hljs-string">'tweet-message'</span>,{
    <span class="hljs-attr">props</span>: {
        <span class="hljs-string">'tweet'</span>: <span class="hljs-built_in">Object</span>,
    },
    <span class="hljs-attr">template</span>: <span class="hljs-string">`
    &lt;div class="tweetMsg"&gt;
        &lt;p&gt;
            {{tweet.text}}
        &lt;/p&gt;

        &lt;div class="tweetDate"&gt;
            &lt;i class="fas fa-calendar-alt fa-sm fa-fw"&gt;&lt;/i&gt;{{tweet.date}}
        &lt;/div&gt;
        &lt;div class="tweet_remove" @click="$emit('remove-tweet', 'index')"&gt;
            &lt;span class="remove"&gt;Delete this tweet &lt;i class="fas fa-trash fa-xs fa-fw"&gt;&lt;/i&gt;&lt;/span&gt;
        &lt;/div&gt;

    &lt;/div&gt;
    `</span>
});
</code></pre>
<p>And we'll change our index.html file as follows:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Show all tweets --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card_tweets"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"tweets"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"tweets.length &gt; 0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Tweets<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tweet-message</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(tweet, index) in tweets"</span>  <span class="hljs-attr">v-bind:tweet</span>=<span class="hljs-string">"tweet"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span> @<span class="hljs-attr">remove-tweet</span>=<span class="hljs-string">"removeTweet(index)"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tweet-message</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>No tweets to show<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now that we've completed our first project, let's learn how to make an API request and how to use the GitHub API to build our final portfolio.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/HanHyGFC6Sc" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-perform-api-calls-with-axios">How to Perform API Calls with Axios</h2>
<p>For our next project, I have created a simple but nice design using Figma that we will use to kick start our portfolio.</p>
<p>Our portfolio will use the GitHub's rest API to pull projects and fill out the design. </p>
<p>You can watch the video on <a target="_blank" href="https://youtu.be/XJEmPr89HA8">YouTube here</a>
and check out the repository on <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/14-axios/">BitBucket</a>.</p>
<h3 id="heading-what-is-a-rest-api">What is a REST API?</h3>
<p>To quote Wikipedia:</p>
<blockquote>
<p>"A REST API is a software architectural style that enables the requesting system to access and manipulate a textual representation of web resources."</p>
</blockquote>
<p>What this means is that our Vue application (the requesting system) will request a textual representation from GitHub of our repositories that we can use later and manipulate to showcase our projects inside our portfolio.</p>
<p>For our final project, we will use a library called Axios that will help us make HTTP requests to the GitHub API. </p>
<p>We can install Axios inside our project in multiple ways. For our example we will keep things simple and use the CDN. </p>
<p>There are also other methods you can use to install Axios. The official documentation for Axios is available <a target="_blank" href="https://www.npmjs.com/package/axios">here</a>
and you can read about how to consume the API in the <a target="_blank" href="https://vuejs.org/v2/cookbook/using-axios-to-consume-apis.html#Base-Example">documentation here</a>.</p>
<h3 id="heading-how-to-install-axios-via-cdn">How to install Axios via CDN</h3>
<p>So let's get started and install Axios via the CDN. We will use the UNPKG CDN and insert a script tag inside our main HTML file. </p>
<p>This CDN will always provide the most up to date version of Axios. Alternatively, we can also specify a different version number. </p>
<p>Let's start by inserting the following script in an index.html file that we will use to send our first HTTP request to the GitHub API.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/axios/dist/axios.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Our final HTML file will look like this now:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>VueJS / GitHub API<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>


<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Axios latest version CDN --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/axios/dist/axios.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- VueJS development version --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The code above is nothing new, but let's look at it piece by piece.</p>
<p>We have a basic HTML structure. Before the closing body tag, we've placed two script tags, one for Axios and one for VueJs. </p>
<p>In the body, we created a root element for the Vue application that we called <code>#app</code>.</p>
<p>Finally, before the end of the body tag, we placed a new script tag that points to the file where we will write our code, the main.js file.</p>
<p>Now we have all the building blocks to make our first API call and request data from the GitHub API.</p>
<p>But before that let's quickly see what an HTTP request actually is and what kind of requests we can make.</p>
<h3 id="heading-what-is-an-http-request">What is an HTTP request?</h3>
<p>HTTP stands for Hypertext transfer protocol. It is an application-layer protocol designed for communications between two points:</p>
<ol>
<li>a web client (the browser) </li>
<li>a web server</li>
</ol>
<p>This protocol allows transmission of data like HTML files and. It defines verbs also known as methods that you can use to perform specific actions on a given resource.</p>
<p>The method or verb that we will use for our project is the <code>GET</code> method, that, as you might have guessed, is used to obtain or to get 
a resource from the webserver.</p>
<p>We have also other methods:</p>
<ul>
<li>GET (retrieves data)</li>
<li>POST (sends data)</li>
<li>PUT (updates the entire representation of the data)</li>
<li>PATCH (similar to put but used to partially update data)</li>
<li>DELETE (removes data)</li>
</ul>
<p>Each of these requests performs a specific action on a resource, but there are also other verbs like the HEAD, OPTIONS, CONNECT, and TRACE.</p>
<p>I won't cover HTTP in detail here as it's out of the scope of this guide. But below there are some links to documentation pages 
related to this topic if you want to find out more. </p>
<p>I suggest you to read the following at least:</p>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-the-internet-works/">HTTP Intro</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP Methods</a></li>
</ul>
<h3 id="heading-how-to-perform-a-get-request">How to perform a GET request</h3>
<p>We will use the GET method to perform get requests from the GitHub API. All data we want to request are publicly accessible (the public repositories of a user), therefore we don't have to authenticate our application. </p>
<p>But unauthenticated requests are limited. For the scope of this tutorial, this is perfectly fine. If you plan to put this in production then you might want to look at how to make authenticated requests and obtain an API key from GitHub.</p>
<p>GitHub provides clear and in-depth documentation about its Rest API, including a list of resources that you can request along with their endpoints. We will use the "List repositories for a user" resources available <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#list-repositories-for-a-user">here</a>.</p>
<p>Let's look at the documentation. The first thing we notice is that GitHub gives us a GET endpoint where we can send our HTTP requests <code>/users/{username}/repos</code>. </p>
<p>The placeholder <code>{username}</code> needs to be replaced with the actual username of the user we want to request the list of public repositories from.</p>
<p>From the documentation, we also see that there are other parameters that we can use to refine our request. We will use <code>username</code> that goes in the path and needs to be a string as described in the parameters table under Type. </p>
<p>We can also use the <code>per_page</code> and <code>page</code> parameters to paginate our results.</p>
<p>Let's make the first request and see what we get.</p>
<p>Inside our main.js file, we will create a new Vue instance and add a <code>mounted</code> lifecycle hook where we will perform the HTTP request using Axios.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">el</span>:<span class="hljs-string">'#app'</span>,
    <span class="hljs-attr">data</span>:{
        <span class="hljs-attr">projects</span>: [],
        <span class="hljs-attr">perPage</span>: <span class="hljs-number">20</span>,
        <span class="hljs-attr">page</span>: <span class="hljs-number">1</span>
    },
    mounted(){

         axios
         .get(<span class="hljs-string">`https://api.github.com/users/fabiopacifici/repos?per_page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.perPage}</span>&amp;page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.page}</span>`</span>)
         .then(
            <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(response);
                <span class="hljs-built_in">this</span>.projects = response.data;
            }
        )
        .catch(<span class="hljs-function"><span class="hljs-params">error</span>=&gt;</span> {<span class="hljs-built_in">console</span>.log(error);})
    }
});
</code></pre>
<p>Let's break this code down. First, we have created a new Vue instance. Then we used the <code>el</code> property and assigned it a root HTML element. </p>
<p>Then we have defined a <code>data</code> object and the properties that we will use later to perform the HTTP request and handle the response.</p>
<p>After the data object, we have defined a lifecycle hook that will use to run our code once the root element has been mounted.</p>
<p>Inside the <code>mounted</code> method, it's time to use Axios and perform an HTTP request. </p>
<p>Axios is a promise-based HTTP client. When we use the get method to request our data from the GitHub API it will return a promise that needs to be handled. </p>
<p>We do this using the syntax <code>axios.get()</code> to perform the request, then we handle its response using the <code>.then()</code> method on the promise. </p>
<p>If our request fails the <code>.catch()</code> method will handle the error and, in this case, show the error message on the console.</p>
<p>Promises are out of the scope of this guide, but if you want to learn more, you can check out <a target="_blank" href="https://www.freecodecamp.org/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/">this detailed article here</a>.</p>
<p>Inside the <code>.get()</code> method we have put the URL including a query string that uses <code>per_page</code> and <code>page</code> parameters to submit our request. Inside the <code>.then()</code> method we handled the response. The response parameter is given to us by the promise and we use an arrow function to handle it.</p>
<pre><code class="lang-js">response =&gt; {
                <span class="hljs-built_in">console</span>.log(response);
                <span class="hljs-built_in">this</span>.projects = response.data;
            }
</code></pre>
<p>The get method returns a promise. Here we simply handled its <code>response</code> with an arrow function where <code>response</code> is the return value that we obtained by calling <code>axios.get()</code>.</p>
<p>We logged the response object to the console. Then we assigned its content, the <code>response.data</code>, to our <code>projects</code> property so that we can later retrieve each project and show them onto the page as usual with a <code>v-for</code> directive.</p>
<h3 id="heading-how-to-show-each-project">How to show each project</h3>
<p>Now it's time to show our projects inside the portfolio. We can do that with the v-for directive.</p>
<p>The projects property in this case contains an array of objects. Each object has its properties that we can use to populate our template.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'app'</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projects"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>{{project.full_name}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"author"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"50px"</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"project.owner.avatar_url"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"me"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"view"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:href</span>=<span class="hljs-string">"project.html_url"</span>&gt;</span>View<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Here we use the v-for directive to loop over the array of projects.
Now the <code>project</code> variable contains an object that represents a single repository from the GitHub account.</p>
<p>Looking at the response object we know that we can grab a number of properties. So we picked <code>full_name</code>, the full name for the repository, <code>owner.avatar_url</code>, the URL of the profile's avatar, and <code>html_url</code> that is the actual URL of our repository. That's all we need for now. </p>
<p>If we now look at the page we will immediately see all repositories from our account.</p>
<p>Now that we know how to make an HTTP request with Axios and get data from GitHub, we are almost ready to start building our portfolio. </p>
<p>In the next section, we are going to look at another Vue library called Vue-router that we will use in our final project.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/XJEmPr89HA8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-to-handle-routing-with-vuerouter">How to Handle Routing with VueRouter</h2>
<p>Our portfolio will surely have more than one page, so we need a system that understands where to send the user when, for instance, they click a link in the navbar for a specific page. </p>
<p>For that Vue has an official routing package that can help us do just that and build a single page application.</p>
<p>A single page application is an application that doesn't refresh the page when a user visits a new page so that the user experience is more fluid.</p>
<p>As for Vue and Axios, we need to install this library and we do that via its CDN. But as always, there are also other methods depending on your needs. I just want to keep things simple for now, so let's start by placing the CDN script tag inside the HTML file and learn the basics of this new library.</p>
<p>You can watch the tutorial on <a target="_blank" href="https://youtu.be/T_avTRFAEAg">YouTube here</a>
and checkout the repository on <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/15-routing/">BitBucket</a>.</p>
<p>You can also see the Vue Router Documentation <a target="_blank" href="https://router.vuejs.org/installation.html#direct-download-cdn">here</a>.</p>
<h3 id="heading-how-to-install-vue-router-via-cdn">How to install Vue Router via CDN</h3>
<p>Let's take our previous example index.html and after the VueJS CDN will point to the router <code>https://unpkg.com/vue-router@3.4.9/dist/vue-router.js</code>.</p>
<pre><code class="lang-html">
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>VueJS / GitHub API<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span> 
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projects"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>{{project.full_name}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"author"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"50px"</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"project.owner.avatar_url"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"me"</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"view"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:href</span>=<span class="hljs-string">"project.html_url"</span>&gt;</span>View<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- Axios latest version CDN --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/axios/dist/axios.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- VueJS development version --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Vue Router CDN --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue-router@3.4.9/dist/vue-router.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Main scrip file --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-use-vue-router">How to use Vue Router</h3>
<p>Now our app has access to the router system and we can add a couple of routes for our application.</p>
<p>We can do so using the <code>router-link</code> component provided by the library and its <code>to</code> attribute to point the link to a specific page.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Create a router link using the 'router-link' component and set the path using the 'to' attribute --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>&gt;</span>Projects<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Render the component for the corresponding route --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">router-view</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>
</code></pre>
<p>We also used the router-view component that will render a specific component for each route.</p>
<p>Now we need to do something inside our JavaScript file to make this work. </p>
<p>Let's see the steps we need to take:</p>
<ul>
<li>Define route components</li>
<li>Define routes</li>
<li>Create a Vue router instance</li>
<li>Create and mount the Vue root instance.</li>
</ul>
<p>First, we need to define our components that we'll use from each route to render the content of the page.</p>
<p>We will create two components, one for the home page and one for the projects page.</p>
<p>To simplify the steps, we will keep everything in the same file and refactor later on. </p>
<p>Let's create the first two basic components to see if the router works:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Create Route components</span>
<span class="hljs-keyword">const</span> Home = {<span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;div&gt;My Portfolio&lt;/div&gt;'</span>} 
<span class="hljs-keyword">const</span> Projects = {<span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;div&gt; Projects &lt;/div&gt;'</span>}
</code></pre>
<p>Now let's follow the remaining steps and define the routes, create the vue router instance, and create and mount the Vue root instance.</p>
<pre><code class="lang-js">
<span class="hljs-comment">// Define some routes</span>
<span class="hljs-keyword">const</span> routes = [
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>, <span class="hljs-attr">component</span>: Home},
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/projects'</span>, <span class="hljs-attr">component</span>: Projects}
];
<span class="hljs-comment">// Create the router instance and pass the routes to it</span>
<span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({
<span class="hljs-attr">routes</span>: routes
});
<span class="hljs-comment">// Create and mount the root instance.</span>

<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    router 
}).$mount(<span class="hljs-string">'#app'</span>);
</code></pre>
<p>That's it. If you visit the homepage you will see two navigation links and the site content will change accordingly.</p>
<p>Let's put it all together and start building our portfolio.</p>
<p>From the previous example in the Axios section, we requested from the GitHub API all public repositories for a user and rendered name, user avatar, and project URL onto the page. </p>
<p>Let's move some of that logic inside our application that uses routes.</p>
<p>The main changes that we need to make here are:</p>
<ul>
<li>move the HTML markup inside the <code>template</code> property of the project's component</li>
<li>move the <code>data</code> properties inside the <code>data</code> object of the component</li>
<li>move the code we wrote in the mounted hook inside our component.</li>
</ul>
<p>The final code looks something like this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Define route components</span>

<span class="hljs-keyword">const</span> Home = {<span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;div&gt;My Portfolio&lt;/div&gt;'</span>} 
<span class="hljs-keyword">const</span> Projects = {

    <span class="hljs-attr">template</span>: <span class="hljs-string">`&lt;div&gt; 
         &lt;div v-for="project in projects"&gt;
            &lt;h2 class="title"&gt;{{project.full_name}}&lt;/h2&gt;

            &lt;div class="author"&gt;
                &lt;img width="50px" :src="project.owner.avatar_url" alt="me"&gt;
            &lt;/div&gt;
            &lt;div class="view"&gt;
                &lt;a :href="project.html_url"&gt;View&lt;/a&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;`</span>,
    data(){
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">projects</span>: [],
            <span class="hljs-attr">perPage</span>: <span class="hljs-number">20</span>,
            <span class="hljs-attr">page</span>: <span class="hljs-number">1</span>
        }
    }, 
    mounted(){

         axios
         .get(<span class="hljs-string">`https://api.github.com/users/fabiopacifici/repos?per_page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.perPage}</span>&amp;page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.page}</span>`</span>)
         .then(
            <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
                <span class="hljs-comment">//console.log(response);</span>
                <span class="hljs-built_in">this</span>.projects = response.data;
            }
        )
        .catch(<span class="hljs-function"><span class="hljs-params">error</span>=&gt;</span> {<span class="hljs-built_in">console</span>.log(error);})
    }
} 

<span class="hljs-comment">// Define some routes</span>
<span class="hljs-keyword">const</span> routes = [
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>, <span class="hljs-attr">component</span>: Home},
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/projects'</span>, <span class="hljs-attr">component</span>: Projects}
];
<span class="hljs-comment">// Create the router instance and pass the routes to it</span>
<span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({
<span class="hljs-attr">routes</span>: routes
});
<span class="hljs-comment">// Create and mount the root instance.</span>

<span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue({
    router 
}).$mount(<span class="hljs-string">'#app'</span>);
</code></pre>
<p>The HTML file remains the same:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'app'</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>&gt;</span>Projects<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">router-view</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now that we have a base to work with, let's improve it. We will use a design prototype I made using Figma and add some functionalities to our portfolio to make it look nice.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/T_avTRFAEAg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-final-project-how-to-build-a-portfolio-with-vuejs-vuerouter-axios-github-api-and-deploy-to-netlify">Final Project – How to Build a Portfolio with VueJS, VueRouter, Axios, GitHub API and deploy to Netlify</h2>
<p>We are ready to build our final project! For our Vue-folio, we will start from where we left off in the previous section.</p>
<p>We will build a single-page application that has two routes, one for the home page and one for the projects page. </p>
<p>Below are the building blocks:</p>
<ul>
<li>Vuejs </li>
<li>Vue router</li>
<li>Axios</li>
<li>GitHub rest API</li>
<li>portfolio design</li>
</ul>
<p>You can watch this tutorial on <a target="_blank" href="https://youtu.be/I6hQnWQU4rQ">YouTube here</a> and check out the repository on <a target="_blank" href="https://bitbucket.org/fbhood/how-to-vuejs/src/master/16-final-project-portfolio/">BitBucket here</a>.</p>
<h3 id="heading-project-structure">Project structure</h3>
<p>To speed things up we will just copy the code we wrote in the previous section.</p>
<p>The project structure will be the following:</p>
<pre><code>|-- index.html
|-- assets/
    |-- css/
        |-- style.css
    |-- js/
        |-- main.js
    |-- img/
</code></pre><h3 id="heading-indexhtml-file">index.html file</h3>
<p>The index.html file is a little different from what we had in the previous section. Here, we will place only the router-view component that is responsible for showing the component matching a given route. </p>
<p>Then we will place the actual <code>route-links</code> inside each component to make sure we have the desired result as per the design.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Vuefolio<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;400;900&amp;display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://use.fontawesome.com/releases/v5.1.1/css/all.css"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./assets/css/style.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Render the component for the corresponding route --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-view</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span> © Developed by <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fabiopacifici.com"</span>&gt;</span>Fabio Pacific<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Axios --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/axios/dist/axios.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- VueJS development version --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Vue Router --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Main Js file --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/js/main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-stylecss-file">style.css file</h3>
<p>Since this is not going to be a CSS tutorial, for the CSS part you can simply copy the code from the repository file if you are following along.</p>
<pre><code class="lang-css">
    <span class="hljs-comment">/* Utility Classes */</span>
    <span class="hljs-selector-class">.d_none</span> {
        <span class="hljs-attribute">display</span>: none;
    }
    <span class="hljs-selector-class">.d_flex</span> {
        <span class="hljs-attribute">display</span>: flex;
    }
    <span class="hljs-selector-class">.container</span> {
        <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1170px</span>;
        <span class="hljs-attribute">margin</span>: auto;
    }
    <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">color</span>: white;
    } 
    <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
        <span class="hljs-attribute">color</span>:<span class="hljs-number">#DB5461</span>;

    }
    <span class="hljs-selector-class">.loading</span> {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
    }
    <span class="hljs-comment">/* END Utility Classes */</span>
    <span class="hljs-comment">/* Components */</span>
    <span class="hljs-selector-class">.bio__media</span> {
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">justify-content</span>: flex-start;
        <span class="hljs-attribute">align-items</span>: center;
        <span class="hljs-attribute">text-align</span>: left;
    }
    <span class="hljs-selector-class">.bio__media</span> <span class="hljs-selector-tag">img</span> {
        <span class="hljs-attribute">height</span>: <span class="hljs-number">120px</span>;
    }
    <span class="hljs-selector-class">.bio__media__text</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
    }
    <span class="hljs-selector-class">.bio__media__text</span> <span class="hljs-selector-tag">h1</span>{
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">36px</span>;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;

    }
    <span class="hljs-selector-class">.bio__media__text</span> <span class="hljs-selector-tag">p</span> {
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
        <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5rem</span>;

    }

    <span class="hljs-selector-class">.card__custom</span> {
        <span class="hljs-attribute">position</span>: relative;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">300px</span>;
        <span class="hljs-attribute">min-height</span>: <span class="hljs-number">300px</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
        <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">3rem</span>;
        <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
        <span class="hljs-attribute">flex-basis</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> /<span class="hljs-number">2</span>);
        <span class="hljs-attribute">align-items</span>: center;
        <span class="hljs-attribute">justify-content</span>: space-between;
    }
    <span class="hljs-selector-class">.card__custom</span> &gt; <span class="hljs-selector-class">.card__custom__text</span> {
        <span class="hljs-attribute">max-width</span>: <span class="hljs-built_in">calc</span>((<span class="hljs-number">100%</span> / <span class="hljs-number">3</span>) *<span class="hljs-number">2</span>);
        <span class="hljs-attribute">text-align</span>: right;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-direction</span>: column;
        <span class="hljs-attribute">justify-content</span>: space-around;
        <span class="hljs-attribute">overflow</span>: hidden;

    }
    <span class="hljs-selector-class">.card__custom__img</span> {

        <span class="hljs-attribute">position</span>: absolute;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
        <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(../img/cards_bg_img.svg);
        <span class="hljs-attribute">background-position</span>: center;
        <span class="hljs-attribute">background-repeat</span>: no-repeat;
        <span class="hljs-attribute">background-size</span>: contain;
        <span class="hljs-attribute">display</span>: inline-block;
        <span class="hljs-attribute">z-index</span>: -<span class="hljs-number">1</span>;
        <span class="hljs-attribute">left</span>: <span class="hljs-number">60%</span>;
        <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">85px</span> <span class="hljs-number">0</span> <span class="hljs-number">100px</span> <span class="hljs-number">25px</span>;

    }
    <span class="hljs-selector-class">.card_custom__button</span> <span class="hljs-selector-tag">a</span>, <span class="hljs-selector-class">.btn_load_more</span> {
        <span class="hljs-attribute">background</span>: <span class="hljs-number">#F1EDEE</span>;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid <span class="hljs-number">#3D5467</span>;
        <span class="hljs-attribute">box-sizing</span>: border-box;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">54px</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1rem</span>;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#3D5467</span>;
    }
    <span class="hljs-selector-class">.card_custom__button</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span>, <span class="hljs-selector-class">.btn_load_more</span><span class="hljs-selector-pseudo">:hover</span> {
        <span class="hljs-attribute">cursor</span>: pointer;
        <span class="hljs-attribute">background</span>: <span class="hljs-number">#324555</span>;
        <span class="hljs-attribute">color</span>: white;
        <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#DB5461</span>;
        <span class="hljs-attribute">transition</span>: <span class="hljs-number">1s</span>;
    }
    <span class="hljs-selector-class">.card__custom__text</span> <span class="hljs-selector-tag">h3</span> {
        <span class="hljs-attribute">text-transform</span>: uppercase;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
    }
    <span class="hljs-comment">/* END Componenet */</span>
    * {
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
        <span class="hljs-attribute">box-sizing</span>: border-box;
    }

    <span class="hljs-selector-tag">body</span>{
        <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Raleway'</span>, Arial, Helvetica, sans-serif;
        <span class="hljs-attribute">color</span>: white;
        <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">116.82deg</span>, #<span class="hljs-number">3</span>D5467 <span class="hljs-number">0%</span>, #<span class="hljs-number">1</span>A232B <span class="hljs-number">99.99%</span>, #<span class="hljs-number">333333</span> <span class="hljs-number">100%</span>);

    }
    <span class="hljs-selector-tag">a</span> {
    <span class="hljs-attribute">text-decoration</span>: none;   
    }

    <span class="hljs-comment">/* Home Page */</span>
    <span class="hljs-selector-tag">main</span><span class="hljs-selector-id">#home</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
        <span class="hljs-attribute">min-height</span>: <span class="hljs-number">600px</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">justify-content</span>: center;
        <span class="hljs-attribute">align-items</span>: center;
    }
    <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> {
        <span class="hljs-attribute">text-align</span>: center;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</span>;
        <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5rem</span>;
    }
    <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h1</span> {
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">36px</span>;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;
    }
    <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h3</span> {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">28px</span>;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;

    }
    <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h3</span>  {
        <span class="hljs-attribute">font-style</span>: normal;
        <span class="hljs-attribute">line-height</span>: <span class="hljs-number">42px</span>;
        <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">0.115em</span>;

    }
    <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> <span class="hljs-selector-tag">p</span> {
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">22px</span>;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
    }
    <span class="hljs-selector-class">.skills_projects_link</span> {
        <span class="hljs-attribute">position</span>: relative;
    }
    <span class="hljs-selector-class">.skills_projects_link</span> &gt; <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">text-transform</span>: uppercase;
        <span class="hljs-attribute">color</span>: white;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
        <span class="hljs-attribute">line-height</span>: <span class="hljs-number">21px</span>;

    }
    <span class="hljs-selector-class">.skills_projects_link</span> &gt; <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;
        <span class="hljs-attribute">transition</span>: all <span class="hljs-number">0.5s</span> ease-in-out;

    }
    <span class="hljs-selector-class">.skills_projects_link</span> &gt; <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span><span class="hljs-selector-pseudo">::after</span> {
        <span class="hljs-attribute">position</span>: absolute;
        <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
        <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">margin</span>: auto;
        <span class="hljs-attribute">text-align</span>: center;
        <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">30px</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">2px</span>;
        <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#DB5461</span>;
        <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.5s</span> ease-in-out;

    }

    <span class="hljs-comment">/* Header */</span>
    <span class="hljs-selector-id">#site_header</span> {
        <span class="hljs-attribute">text-align</span>: center;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">0</span>;
        <span class="hljs-attribute">justify-content</span>: space-between;
        <span class="hljs-attribute">align-items</span>: center;
    }
    <span class="hljs-selector-id">#site_header</span> &gt; <span class="hljs-selector-tag">h1</span> {
        <span class="hljs-attribute">text-transform</span>: uppercase;
    }
    <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span> {
            <span class="hljs-attribute">color</span>: <span class="hljs-number">#e2e2e2</span>;
        <span class="hljs-attribute">text-transform</span>: uppercase;
        <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    }
    <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;
    }
    <span class="hljs-comment">/* Portfolio Page Section */</span>

    <span class="hljs-selector-id">#portfolio</span> {
        <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">4rem</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-wrap</span>: wrap;
        <span class="hljs-attribute">align-items</span>: center;
        <span class="hljs-attribute">justify-content</span>: space-around;
    }
    <span class="hljs-selector-class">.btn_load_more</span> {

    }
    <span class="hljs-comment">/* Skills */</span>

    <span class="hljs-selector-id">#skills_section</span> {
        <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">4rem</span>;
        <span class="hljs-attribute">min-height</span>: <span class="hljs-number">300px</span>;
        <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(../img/skills_bg.svg);
        <span class="hljs-attribute">background-repeat</span>: no-repeat;
        <span class="hljs-attribute">background-size</span>: contain;
        <span class="hljs-attribute">background-position</span>: top left;
    }
    <span class="hljs-selector-id">#skills_section</span> <span class="hljs-selector-tag">h2</span> {
        <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">180px</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">44px</span>;
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#F1EDEE</span>;
        <span class="hljs-attribute">line-height</span>: <span class="hljs-number">2rem</span>;

    }
    <span class="hljs-selector-id">#skills_section</span> <span class="hljs-selector-tag">ul</span> {
        <span class="hljs-attribute">list-style</span>: none;
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span> <span class="hljs-number">120px</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-wrap</span>: wrap;

    }
    <span class="hljs-selector-id">#skills_section</span> <span class="hljs-selector-tag">ul</span>  <span class="hljs-selector-tag">li</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">0.5rem</span>;
        <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#DB5461</span>;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid <span class="hljs-number">#3D5467</span>;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">35px</span>;
    }



    <span class="hljs-selector-class">.avatar</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">30px</span>;
        <span class="hljs-attribute">height</span>: auto;
        <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
            <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1rem</span>;

    }




    <span class="hljs-selector-class">.card__back</span> {
        <span class="hljs-attribute">display</span>: none;
    }
    <span class="hljs-selector-class">.rotate__card</span> {
        <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate3d</span>(<span class="hljs-number">360</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">180deg</span>);
    }
    <span class="hljs-comment">/* Site Footer */</span>

    <span class="hljs-selector-tag">footer</span> {
        <span class="hljs-attribute">text-align</span>: center;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">0</span>;
    }



    <span class="hljs-comment">/* Media Query  */</span>

    <span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">475px</span>) {
        <span class="hljs-selector-class">.card</span> {
            <span class="hljs-attribute">flex-basis</span>: <span class="hljs-number">100%</span>;
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
        }
    }
</code></pre>
<h2 id="heading-mainjs-file-basic-structure">Main.js file basic structure</h2>
<p>Inside the main.js file, we have the core of our single page application. 
Here we will define the route components that need to be rendered for each view/page, the homepage, and projects components. </p>
<p>Then we will define two routes, one for the homepage and one for the projects page, create a router instance, and pass it to the routes. Finally, we will create a new Vue instance and pass to it the router instance and mount the root HTML element.</p>
<p>Let's start with the route components.</p>
<h3 id="heading-how-to-define-components-for-each-view">How to define components for each view</h3>
<p>The homepage component is fairly simple. </p>
<pre><code class="lang-js"><span class="hljs-comment">// Homepage component</span>
<span class="hljs-keyword">const</span> Home = {
    <span class="hljs-attr">template</span>: 
    <span class="hljs-string">`&lt;main id="home"&gt;
        &lt;div class="about__me"&gt;
            &lt;img src="./assets/img/avatar.svg" alt=""&gt;
            &lt;h1&gt;John Doe&lt;/h1&gt;
            &lt;h3&gt;Python Expert&lt;/h3&gt;
            &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. &lt;/p&gt;

            &lt;div class="skills_projects_link"&gt;
                &lt;router-link to="/projects"&gt;Projects/Skills&lt;/router-link&gt; 
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/main&gt;`</span>
}
</code></pre>
<p>Let's break it down. First, we create a Home constant that will hold the router component object. </p>
<p>Inside the object, the only thing we will put is the template property with some markup to render our page. The main thing to notice here is the router-link component that will point to the /projects route from the homepage.</p>
<p>Next, let's create a route component for the projects page. We have a lot to do here so for now let's just add some boilerplate code – we will come back to it later and write out step by step all the logic. </p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Projects = {
    <span class="hljs-attr">template</span>: 
    <span class="hljs-string">`&lt;div&gt;
        &lt;h1&gt;Projects&lt;/h1&gt;
    &lt;/div&gt;`</span>,
    data() { 
        <span class="hljs-keyword">return</span> {
                <span class="hljs-comment">// Data object here</span>
            }
    },
    <span class="hljs-attr">methods</span>: {
        <span class="hljs-comment">// All methods here</span>
    },
    mounted(){  
        <span class="hljs-comment">// Lifecycle hook      </span>

    }
}
</code></pre>
<p>The Projects route components have a <code>template</code> property that so far holds a basic markup that only spit out an <code>h1</code> title.</p>
<p>After that there is the component's data method that returns an empty object, then an empty methods object and an empty lifecycle hook.</p>
<p>That's all we need, for now, so let's move on and define the rest of the building blocks, the routes, the router and the Vue instances.</p>
<h3 id="heading-how-to-define-the-routes-router-and-vue-instance">How to define the routes, router, and Vue instance</h3>
<p>Now that we have two components to render on our main pages we can move forward to the next steps:</p>
<ul>
<li>define routes</li>
<li>create the router instance</li>
<li>create and mount the Vue instance</li>
</ul>
<p>First, let's define our two routes and link the components.</p>
<pre><code class="lang-js">
<span class="hljs-comment">// Define routes</span>
<span class="hljs-keyword">const</span> routes = [
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>, <span class="hljs-attr">component</span>: Home},
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/projects'</span>, <span class="hljs-attr">component</span>: Projects},
];
</code></pre>
<p>In the code, we have defined a new constant called routes. In it, we defined two routes as an array of objects. </p>
<p>Each object has two properties:</p>
<ul>
<li>path</li>
<li>component</li>
</ul>
<p>The first object is for the homepage. Its path will respond to requests made to our website base URL, like https://fabiopacifici.com/.</p>
<p>Then the component property links this page to the route's component called <code>Home</code> that we defined in the previous step. </p>
<p>The second object is for the projects page. The path responds to requests made to <code>/projects</code> and it's linked to the <code>Projects</code> route component.</p>
<p>Now that we have our routes:</p>
<pre><code class="lang-js">
<span class="hljs-comment">// create the router instance</span>
<span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({
    routes
})
</code></pre>
<p>Above we used the ES6 syntax that allows us to just put the name of the variable holding the routes since it is equal to the name of the property that we needed to use. It's actually the same as writing <code>routes: routes</code>.</p>
<p>Now, we create a Vue instance. Inject the router instance inside it and finally mount the root element. </p>
<pre><code class="lang-js">
<span class="hljs-comment">// create and mount the vue instance</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue({
    router
}).$mount(<span class="hljs-string">'#app'</span>);
</code></pre>
<p>Done! We now have everything in place to start building our portfolio and complete the Projects route component.</p>
<h2 id="heading-how-to-build-the-main-projects-route-component">How to Build the Main Projects Route Component</h2>
<p>We will start working on the data object. Here we need to define properties that will hold all our projects once we fetch data from the git hub API.</p>
<h3 id="heading-the-data-object">The data object</h3>
<p>To keep things easier I have intentionally limited results to 20. If you feel this isn't enough you can change the code as you like. </p>
<p>You can implement pagination for your results by increasing the page property that will be passed to the query string or return more results per page by increasing the value of the <code>perPage</code> property.</p>
<pre><code class="lang-js">data() { 
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">projects</span>: [],
        <span class="hljs-attr">projectsList</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">skills</span>: [],
        <span class="hljs-attr">projectsCount</span>: <span class="hljs-number">5</span>,
        <span class="hljs-attr">perPage</span>: <span class="hljs-number">20</span>,
        <span class="hljs-attr">page</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">errors</span>: <span class="hljs-literal">false</span>,
        }
    },
</code></pre>
<p>As we learned in the section where we used Axios to fetch data from the GitHub REST API, there are a few properties we need to define. </p>
<p>The component's data function returns an object with a <code>projects</code> property where we will store all projects we fetch from GitHub.</p>
<p>Then we add a <code>projectsList</code> property that holds only a few projects at a time. We will use this property later to implement a very simple
load more feature in combination with the <code>projectsCount</code> property.</p>
<p>Then we have a <code>skills</code> property where we will store all languages used to build our projects. </p>
<p>We'll use the <code>perPage: 20</code> and <code>page: 1</code> properties to build the query string used to fetch data from GitHub. It will take 20 projects and 
return only the first page of results unless we change these values.</p>
<p>Finally, we have a <code>loading: true</code> property that we will use to check if the page is fetching data and an <code>errors: false</code> property that shows an error message in case we are unable to connect to the GitHub server.</p>
<p>In the next step, we will start working on all methods required to make our application work.</p>
<h3 id="heading-the-fetch-all-data-method">The fetch all data method</h3>
<p>The first method is the one we will use to fetch data from GitHub.</p>
<p>This method will make the Ajax call to the GitHub rest API using Axios and store the response in a property of the Vue instance:</p>
<pre><code class="lang-js">
 <span class="hljs-attr">fetchData</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            axios
            .get(<span class="hljs-string">`https://api.github.com/users/fbhood/repos?per_page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.perPage}</span>&amp;page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.page}</span>`</span>)
            .then(
                <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {

                    <span class="hljs-built_in">this</span>.projects = response.data;
                    <span class="hljs-built_in">this</span>.projects.forEach(<span class="hljs-function"><span class="hljs-params">project</span> =&gt;</span>{
                        <span class="hljs-keyword">if</span> (project.language !== <span class="hljs-literal">null</span> &amp;&amp; ! <span class="hljs-built_in">this</span>.skills.includes(project.language)) { 
                            <span class="hljs-built_in">this</span>.skills.push(project.language)
                        };
                    });
                }
            )
            .catch(<span class="hljs-function"><span class="hljs-params">error</span>=&gt;</span> {
                <span class="hljs-built_in">console</span>.log(error);
                <span class="hljs-built_in">this</span>.errors = <span class="hljs-literal">true</span>;
            })
            .finally(<span class="hljs-function">() =&gt;</span> { 
                <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">false</span>
                <span class="hljs-built_in">this</span>.getProjects();
            })
        },
</code></pre>
<p>Let's break this down. First, we defined a method called <code>fetchData: function(){}</code>. This method uses Axios to make an API call to the
REST API. </p>
<p>In the <code>.get()</code> method we have built the URL also using the properties <code>perPage</code> and <code>page</code> as part of the query string.</p>
<p>The get method returns a promise so we used the <code>.then()</code> method on the promise to handle the response using an arrow function <code>response =&gt; {}</code>.</p>
<p>Inside the arrow function, we stored the response data inside the projects property of the Vue instance using <code>this.projects = response.data;</code>.</p>
<p>Next, we used a <code>forEach</code> loop to iterate over each project and store the language used in the repository as a skill using the code below:</p>
<pre><code class="lang-js"><span class="hljs-built_in">this</span>.projects.forEach(<span class="hljs-function"><span class="hljs-params">project</span> =&gt;</span>{
    <span class="hljs-keyword">if</span> (project.language !== <span class="hljs-literal">null</span> &amp;&amp; ! <span class="hljs-built_in">this</span>.skills.includes(project.language)) { 
        <span class="hljs-built_in">this</span>.skills.push(project.language)
    };
});
</code></pre>
<p>We chained a <code>.catch</code> method to handle an error in case we are unable to connect to the rest API and fetch data. We will log the error to the
console and update the value of the <code>errors</code> property to true so that we can show a custom error message to the user later on. </p>
<p>Finally, we chained the <code>.finally()</code> method that will be executed after the response has been handled. We also updated the <code>loading</code> property and set it to false so that we can show the results to the user. </p>
<p>Inside the <code>finally</code> method we can also call a method (that we still have to create) and that we will use to slice the results later. </p>
<p>Let's build it.</p>
<h3 id="heading-the-get-projects-method">The get projects method</h3>
<p>This method takes a portion of the projects we actually stored in the <code>projects</code> property. We can use the <code>projectsList</code> property to store the slice and later implement a method to increment them with a show more button.</p>
<pre><code class="lang-js">
<span class="hljs-attr">getProjects</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{

    <span class="hljs-built_in">this</span>.projectsList = <span class="hljs-built_in">this</span>.projects.slice(<span class="hljs-number">0</span>, <span class="hljs-built_in">this</span>.projectsCount);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.projectsList;

},
</code></pre>
<p>The getProjects method takes a portion of all projects stored in the <code>projects</code> property using the array slice method in conjunction with
the property <code>projectsCount</code> that is set to five. So it will store in there only the first five results and return them.</p>
<p>To add five more projects to the <code>projectsList</code> property we will also need a method that the user can call when he clicks on the load more button. Let's create it.</p>
<h3 id="heading-the-load-more-projects-method">The load more projects method</h3>
<p>The load more method will first check if the length of the <code>projects</code> array is less than or equal to the length of the <code>projectsList</code> array. Then, if not, it will increment the value of the <code>projectsCount</code> property by five and then take a bigger slice from the <code>projects</code> property.</p>
<pre><code class="lang-js">
loadMore(){

    <span class="hljs-keyword">if</span>(<span class="hljs-built_in">this</span>.projectsList.length &lt;= <span class="hljs-built_in">this</span>.projects.length){
        <span class="hljs-built_in">this</span>.projectsCount += <span class="hljs-number">5</span>;
        <span class="hljs-built_in">this</span>.projectsList = <span class="hljs-built_in">this</span>.projects.slice(<span class="hljs-number">0</span>, <span class="hljs-built_in">this</span>.projectsCount)
    }


}
</code></pre>
<h3 id="heading-build-the-template">Build the template</h3>
<p>In the template property of the <code>Projects</code> component, we can start with the header section. We'll also put in there two <code>router-link</code> components for the pages navigation:</p>
<pre><code class="lang-html">`<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"site_header"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container d_flex"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bio__media"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/img/avatar.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bio__media__text"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>John Doe<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Python Expert<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet consectetur adipisicing elit. <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/'</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>&gt;</span>Project<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fab fa-github fa-lg fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Next, we can continue working on the template and create the main section.
We will put the following markup always in the main template div, right under the header closing tag.</p>
<p>Let's start by placing the main container:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Show an error message if the REST API doensn't work --&gt;</span>
    <span class="hljs-comment">&lt;!-- Otherwise show  a section for our portfolio projects and skills section--&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>Inside the container, let's use the v-if-else directives to show an error message or the projects section:</p>
<pre><code class="lang-html"> <span class="hljs-comment">&lt;!-- Show Errors if the rest api doesn't work --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"error"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"errors"</span>&gt;</span> 
        Sorry! It seems we can't fetch data righ now 😥
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Else show the portfolio section --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"portfolio"</span> <span class="hljs-attr">v-else</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>To make the code work, we used the v-if directive and passed to it the <code>errors</code> property. This property will be set to <code>true</code> if there is an error while we fetch data from GitHub or will be set to <code>false</code> if everything is ok. So the v-else directive will render the portfolio section.</p>
<p>Next, we need to show a 'loading...' message while we fetch data. When done we can use the v-for directive to loop over the results. So right in the portfolio section, we will write another v-if-else directive.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"portfolio"</span> <span class="hljs-attr">v-else</span>&gt;</span>
 <span class="hljs-comment">&lt;!-- Use a v-if directive to show the loading message --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"loading"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"loading"</span>&gt;</span>😴 Loading ... <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- use a v-for directive to loop over the projectsList array --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projectsList"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom"</span> <span class="hljs-attr">v-else</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Here we use the v-if directive <code>&lt;div class="loading" v-if="loading"&gt;😴 Loading ... &lt;/div&gt;</code> to render a loading message. After that the <code>&lt;div v-for="project in projectsList" class="card__custom" v-else&gt;&lt;/div&gt;</code>
has two directives, the v-for directive that we use to loop over the <code>projectsList</code> property and a v-else directive that will show this element when we are done fetching data from GitHub.</p>
<p>Now we can use the <code>project</code> variable to render all project details in our markup:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- use a v-for directive to loop over the projectsList array --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projectsList"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom"</span> <span class="hljs-attr">v-else</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom__text"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- Create a custom method to trim the project name so that it doesn't break the design --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{project.name}}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- Create a custom trimmedText to trim the description --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{project.description}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>                        
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"meta__data d_flex"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"date"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>Updated at<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{new Date(project.updated_at).toDateString()}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"avatar"</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"project.owner.avatar_url"</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom__img"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card_custom__button"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:href</span>=<span class="hljs-string">"project.html_url"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>
            Code
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>To render the project title and desciption we used the propeties <code>poject.name</code> and <code>project.description</code>. But the description and the title will break our design unless we trim them at some point. </p>
<p>Next in the element with class <code>date</code> we rendered the poject data in a readable fomat using the <code>new Data().toDateString()</code> method. </p>
<p>To render the user avatar <code>&lt;img class="avatar" :src="project.owner.avatar_url"&gt;</code> we used the shortcut for the v-bind diective so that we could use the property <code>project.owner.avatar_url</code> to grab the avatar URL. </p>
<p>Finally, to render a button that once clicked redirects the user to the repository page we bound the <code>href</code> attribute to the <code>project.html_url</code> property <code>&lt;a :href="project.html_url" target="_blank"&gt;Code&lt;/a&gt;</code>.</p>
<p>Our project card is complete. The next thing we need to do is render a load more button to show more projects. </p>
<p>We are still working inside the <code>projects</code> section. Right after the project card we can write the following markup</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Render a load more button --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"text-align: center; width:100%"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!loading"</span> &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"projectsList.length &lt; projects.length"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_load_more"</span> <span class="hljs-attr">v-on:click</span>=<span class="hljs-string">"loadMore()"</span>&gt;</span>Load More<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">""</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span>&gt;</span>Visit My GitHub<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The v-if directive first checks if the loading property is set to false. 
If so, we'll use another v-if directive to check if the length of property <code>projectsList</code> is less than the length of the property <code>projects</code>. </p>
<p>If so, it will show a button that uses a v-on directive to listen for clicks 
<code>&lt;button class="btn_load_more" v-on:click="loadMore()"&gt;Load More&lt;/button&gt;</code> and trigger a <code>loadMore()</code> method. Otherwise, we show a link to the GitHub account. </p>
<p>After this, we can show a list of skills related to all the projects:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Show a skills section --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"skills_section"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Development Skills<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"skills"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Loop over the skills property --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"skill in skills"</span>&gt;</span>{{skill}}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Our markup is complete, but we need to improve our code a little as the project title and its description are breaking our design! </p>
<p>Let's create two methods, one to trim the title and one for the description text.</p>
<h3 id="heading-the-trimtext-and-trimtitle-methods">The trimText and trimTitle methods</h3>
<p>The <code>trimTitle</code> method will replace all <code>-</code> and <code>_</code> with a space, and restrict the number of characters to 12. The <code>trimText</code> method instead only reduces the number of characters of the description in excess of 100 characters. </p>
<pre><code class="lang-js">trimTitle: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">text</span>)</span>{
    <span class="hljs-keyword">let</span> title = text.replaceAll(<span class="hljs-string">"-"</span>, <span class="hljs-string">" "</span>).replace(<span class="hljs-string">"_"</span>, <span class="hljs-string">" "</span>)
    <span class="hljs-keyword">if</span>(title.length &gt; <span class="hljs-number">15</span>) {
        <span class="hljs-keyword">return</span> title.slice(<span class="hljs-number">0</span>, <span class="hljs-number">12</span>) + <span class="hljs-string">' ...'</span>
    } <span class="hljs-keyword">return</span> title;

},
<span class="hljs-attr">trimText</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">text</span>)</span>{
    <span class="hljs-comment">//console.log(text.slice(0, 100));</span>
    <span class="hljs-keyword">if</span>(text.length &gt; <span class="hljs-number">100</span>) {
        <span class="hljs-keyword">return</span> text.slice(<span class="hljs-number">0</span>, <span class="hljs-number">100</span>) + <span class="hljs-string">' ...'</span>
    } <span class="hljs-keyword">return</span> text;
},
</code></pre>
<p>With these two methods, now we can update the markup and use them to make sure nothing breaks the design.</p>
<p>Let's update these two lines that will be changed from this:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Create a custom method to trim the project name so that it doesn't break the design --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{project.name}}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Create a custom trimmedText to trim the description --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{project.description}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>To this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{trimedTitle(project.name)}}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{trimedText(project.description)}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Let's put eveything together. The final markup will be the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"site_header"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container d_flex"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bio__media"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/img/avatar.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bio__media__text"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>John Doe<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Python Expert<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet consectetur adipisicing elit. <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/'</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>&gt;</span>Project<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fab fa-github fa-lg fa-fw"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"error"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"errors"</span>&gt;</span> 
            Sorry! It seems we can't fetch data righ now 😥
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"portfolio"</span> <span class="hljs-attr">v-else</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"loading"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"loading"</span>&gt;</span>😴 Loading ... <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"projects"</span> <span class="hljs-attr">v-else</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"project in projectsList"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom"</span> &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom__text"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{trimedTitle(project.name)}}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{trimedText(project.description)}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>                        
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"meta__data d_flex"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"date"</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>Updated at<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{new Date(project.updated_at).toDateString()}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"avatar"</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"project.owner.avatar_url"</span>&gt;</span>

                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__custom__img"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card_custom__button"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:href</span>=<span class="hljs-string">"project.html_url"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>
                            Code
                        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>


                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>


                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"text-align: center; width:100%"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!loading"</span> &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"projectsList.length &lt; projects.length"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_load_more"</span> <span class="hljs-attr">v-on:click</span>=<span class="hljs-string">"loadMore()"</span>&gt;</span>Load More<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">""</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span>&gt;</span>Visit My GitHub<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"skills_section"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Development Skills<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"skills"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"skill in skills"</span>&gt;</span>{{skill}}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>  
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>There is one last thing to do. Since fetching data from GitHub is very fast we don't really see the loading message. Let's set a timeout and delay it by a few seconds – then you can tune it as you like.</p>
<h3 id="heading-the-mounted-lifecycle-hook">The mounted lifecycle hook</h3>
<pre><code> mounted(){  

        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-built_in">this</span>.fetchData, <span class="hljs-number">3000</span> );

    }
</code></pre><p>Inside the mounted lifecycle hook we used <code>setTimeout()</code> and called the <code>fetchData</code> method as the first parameter. Then for the second parameter we specified that this method should be executed after 3000 milliseconds (3seconds). </p>
<h2 id="heading-lets-see-our-final-code-all-toghether">Let's see our final code all toghether</h2>
<p>Index.html file looks like the following:</p>
<pre><code class="lang-html">
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Vuefolio<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;400;900&amp;display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://use.fontawesome.com/releases/v5.1.1/css/all.css"</span>
        <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-O8whS3fhG2OnA5Kas0Y9l3cfpmYjapjI0E4theH4iuMD+pLhbf6JI0jIMfYcK3yZ"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./assets/css/style.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Render the component for the corresponding route --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-view</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span> © Developed by <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fabiopacifici.com"</span>&gt;</span>Fabio Pacific<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Axios --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/axios/dist/axios.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- VueJS development version --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Vue Router --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Main Js file --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/js/main.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>And this is the main.js file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Create route components</span>
<span class="hljs-keyword">const</span> Home = {
    <span class="hljs-attr">template</span>: 
    <span class="hljs-string">`&lt;main id="home"&gt;
        &lt;div class="about__me"&gt;
            &lt;img src="./assets/img/avatar.svg" alt=""&gt;
            &lt;h1&gt;John Doe&lt;/h1&gt;
            &lt;h3&gt;Python Expert&lt;/h3&gt;
            &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. &lt;/p&gt;

            &lt;div class="skills_projects_link"&gt;&lt;router-link to="/projects"&gt;Projects/Skills&lt;/router-link&gt; &lt;/div&gt;
        &lt;/div&gt;
    &lt;/main&gt;`</span>
}
<span class="hljs-keyword">const</span> Projects = {
    <span class="hljs-attr">template</span>: 
    <span class="hljs-string">`&lt;div&gt;
        &lt;header id="site_header" class="container d_flex"&gt;
            &lt;div class="bio__media"&gt;
                &lt;img src="./assets/img/avatar.svg" alt=""&gt;
                &lt;div class="bio__media__text"&gt;
                    &lt;h1&gt;John Doe&lt;/h1&gt;
                    &lt;h3&gt;Python Expert&lt;/h3&gt;
                    &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. &lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;nav&gt;
                &lt;router-link to='/'&gt;Home&lt;/router-link&gt;
                &lt;router-link to="/projects"&gt;Project&lt;/router-link&gt;
                &lt;a href="https://"&gt;
                    &lt;i class="fab fa-github fa-lg fa-fw"&gt;&lt;/i&gt;
                &lt;/a&gt;
            &lt;/nav&gt;
        &lt;/header&gt;

         &lt;main class="container"&gt;
            &lt;div class="error" v-if="errors"&gt; 
                Sorry! It seems we can't fetch data righ now 😥
            &lt;/div&gt;

            &lt;section id="portfolio" v-else&gt;
                &lt;div class="loading" v-if="loading"&gt;😴 Loading ... &lt;/div&gt;
                &lt;div class="projects" v-else&gt;
                     &lt;div v-for="project in projectsList" class="card__custom" &gt;
                        &lt;div class="card__custom__text"&gt;
                            &lt;div&gt;
                                &lt;h3&gt;{{trimedTitle(project.name)}}&lt;/h3&gt;
                                &lt;p&gt;{{trimedText(project.description)}}&lt;/p&gt;                        
                            &lt;/div&gt;

                            &lt;div class="meta__data d_flex"&gt;
                                &lt;div class="date"&gt;
                                    &lt;h5&gt;Updated at&lt;/h5&gt;
                                    &lt;div&gt;{{new Date(project.updated_at).toDateString()}}&lt;/div&gt;
                                &lt;/div&gt;
                                &lt;img class="avatar" :src="project.owner.avatar_url"&gt;

                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;div class="card__custom__img"&gt;&lt;/div&gt;
                        &lt;div class="card_custom__button"&gt;
                            &lt;a :href="project.html_url" target="_blank"&gt;
                                Code
                            &lt;/a&gt;
                        &lt;/div&gt;


                    &lt;/div&gt;


                    &lt;div style="text-align: center; width:100%" v-if="!loading" &gt;
                        &lt;div v-if="projectsList.length &lt; projects.length"&gt;
                            &lt;button class="btn_load_more" v-on:click="loadMore()"&gt;Load More&lt;/button&gt;
                        &lt;/div&gt;
                        &lt;div v-else&gt;
                            &lt;a href="" target="_blank" rel="noopener noreferrer"&gt;Visit My GitHub&lt;/a&gt;
                        &lt;/div&gt;

                    &lt;/div&gt;

                    &lt;div id="skills_section"&gt;
                        &lt;h2&gt;Development Skills&lt;/h2&gt;
                        &lt;ul class="skills"&gt;
                            &lt;li v-for="skill in skills"&gt;{{skill}}&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/section&gt;


        &lt;/main&gt;
    &lt;/div&gt;`</span>,
data() { 
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">data</span>: [],
        <span class="hljs-attr">projects</span>: [],
        <span class="hljs-attr">projectsList</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">skills</span>: [],
        <span class="hljs-attr">projectsCount</span>: <span class="hljs-number">5</span>,
        <span class="hljs-attr">perPage</span>: <span class="hljs-number">20</span>,
        <span class="hljs-attr">page</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">errors</span>: <span class="hljs-literal">false</span>,
        }
    },
    <span class="hljs-attr">methods</span>: {
        <span class="hljs-attr">trimedTitle</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">text</span>)</span>{
            <span class="hljs-keyword">let</span> title = text.replaceAll(<span class="hljs-string">"-"</span>, <span class="hljs-string">" "</span>).replace(<span class="hljs-string">"_"</span>, <span class="hljs-string">" "</span>)
            <span class="hljs-keyword">if</span>(title.length &gt; <span class="hljs-number">15</span>) {
                <span class="hljs-keyword">return</span> title.slice(<span class="hljs-number">0</span>, <span class="hljs-number">12</span>) + <span class="hljs-string">' ...'</span>
            } <span class="hljs-keyword">return</span> title;

        },
        <span class="hljs-attr">trimedText</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">text</span>)</span>{
            <span class="hljs-comment">//console.log(text.slice(0, 100));</span>
            <span class="hljs-keyword">if</span>(text === <span class="hljs-literal">null</span>) {
                <span class="hljs-keyword">return</span> <span class="hljs-string">'This project has no description yet!'</span>;
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(text.length &gt; <span class="hljs-number">100</span>) {
                <span class="hljs-keyword">return</span> text.slice(<span class="hljs-number">0</span>, <span class="hljs-number">100</span>) + <span class="hljs-string">' ...'</span>
            } 
            <span class="hljs-keyword">return</span> text;

        },
        <span class="hljs-attr">getProjects</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{

            <span class="hljs-built_in">this</span>.projectsList = <span class="hljs-built_in">this</span>.projects.slice(<span class="hljs-number">0</span>, <span class="hljs-built_in">this</span>.projectsCount);
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.projectsList;

        },
        <span class="hljs-attr">fetchData</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            axios
            .get(<span class="hljs-string">`https://api.github.com/users/fbhood/repos?per_page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.perPage}</span>&amp;page=<span class="hljs-subst">${<span class="hljs-built_in">this</span>.page}</span>`</span>)
            .then(
                <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
                    <span class="hljs-built_in">this</span>.projects = response.data;
                    <span class="hljs-built_in">this</span>.projects.forEach(<span class="hljs-function"><span class="hljs-params">project</span> =&gt;</span>{
                        <span class="hljs-keyword">if</span> (project.language !== <span class="hljs-literal">null</span> &amp;&amp; ! <span class="hljs-built_in">this</span>.skills.includes(project.language)) { 
                            <span class="hljs-built_in">this</span>.skills.push(project.language)
                        };
                    });
                }
            )
            .catch(<span class="hljs-function"><span class="hljs-params">error</span>=&gt;</span> {
                <span class="hljs-built_in">console</span>.log(error);
                <span class="hljs-built_in">this</span>.errors = <span class="hljs-literal">true</span>;
            })
            .finally(<span class="hljs-function">() =&gt;</span> { 
                <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">false</span>
                <span class="hljs-built_in">this</span>.getProjects();
            })
        }, 
        loadMore(){

            <span class="hljs-keyword">if</span>(<span class="hljs-built_in">this</span>.projectsList.length &lt;= <span class="hljs-built_in">this</span>.projects.length){
                <span class="hljs-built_in">this</span>.projectsCount += <span class="hljs-number">5</span>;
                <span class="hljs-built_in">this</span>.projectsList = <span class="hljs-built_in">this</span>.projects.slice(<span class="hljs-number">0</span>, <span class="hljs-built_in">this</span>.projectsCount)
            }


        }

    },
    mounted(){  

        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-built_in">this</span>.fetchData, <span class="hljs-number">3000</span> );

    }
}

<span class="hljs-comment">// Define routes</span>
<span class="hljs-keyword">const</span> routes = [
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>, <span class="hljs-attr">component</span>: Home},
    {<span class="hljs-attr">path</span>: <span class="hljs-string">'/projects'</span>, <span class="hljs-attr">component</span>: Projects},
];


<span class="hljs-comment">// create the router instance</span>
<span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({
    routes
})

<span class="hljs-comment">// create and mount the vue instance</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue({
    router
}).$mount(<span class="hljs-string">'#app'</span>);
</code></pre>
<p>On the CSS side this is what we have:</p>
<pre><code class="lang-css">
<span class="hljs-comment">/* Utility Classes */</span>
<span class="hljs-selector-class">.d_none</span> {
    <span class="hljs-attribute">display</span>: none;
}
<span class="hljs-selector-class">.d_flex</span> {
    <span class="hljs-attribute">display</span>: flex;
}
<span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1170px</span>;
    <span class="hljs-attribute">margin</span>: auto;
}
<span class="hljs-selector-tag">a</span> {
    <span class="hljs-attribute">color</span>: white;
} 
<span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">color</span>:<span class="hljs-number">#DB5461</span>;

}
<span class="hljs-selector-class">.loading</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
}
<span class="hljs-comment">/* END Utility Classes */</span>
<span class="hljs-comment">/* Components */</span>
<span class="hljs-selector-class">.bio__media</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: flex-start;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">text-align</span>: left;
}
<span class="hljs-selector-class">.bio__media</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">height</span>: <span class="hljs-number">120px</span>;
}
<span class="hljs-selector-class">.bio__media__text</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
}
<span class="hljs-selector-class">.bio__media__text</span> <span class="hljs-selector-tag">h1</span>{
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">36px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;

}
<span class="hljs-selector-class">.bio__media__text</span> <span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5rem</span>;

}

<span class="hljs-selector-class">.card__custom</span> {
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">300px</span>;
    <span class="hljs-attribute">min-height</span>: <span class="hljs-number">300px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">3rem</span>;
    <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
    <span class="hljs-attribute">flex-basis</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> /<span class="hljs-number">2</span>);
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">justify-content</span>: space-between;
}
<span class="hljs-selector-class">.card__custom</span> &gt; <span class="hljs-selector-class">.card__custom__text</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-built_in">calc</span>((<span class="hljs-number">100%</span> / <span class="hljs-number">3</span>) *<span class="hljs-number">2</span>);
    <span class="hljs-attribute">text-align</span>: right;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">justify-content</span>: space-around;
    <span class="hljs-attribute">overflow</span>: hidden;

}
<span class="hljs-selector-class">.card__custom__img</span> {

    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(../img/cards_bg_img.svg);
    <span class="hljs-attribute">background-position</span>: center;
    <span class="hljs-attribute">background-repeat</span>: no-repeat;
    <span class="hljs-attribute">background-size</span>: contain;
    <span class="hljs-attribute">display</span>: inline-block;
    <span class="hljs-attribute">z-index</span>: -<span class="hljs-number">1</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">60%</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">85px</span> <span class="hljs-number">0</span> <span class="hljs-number">100px</span> <span class="hljs-number">25px</span>;

}
<span class="hljs-selector-class">.card_custom__button</span> <span class="hljs-selector-tag">a</span>, <span class="hljs-selector-class">.btn_load_more</span> {
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#F1EDEE</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid <span class="hljs-number">#3D5467</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">54px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#3D5467</span>;
}
<span class="hljs-selector-class">.card_custom__button</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span>, <span class="hljs-selector-class">.btn_load_more</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#324555</span>;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#DB5461</span>;
    <span class="hljs-attribute">transition</span>: <span class="hljs-number">1s</span>;
}
<span class="hljs-selector-class">.card__custom__text</span> <span class="hljs-selector-tag">h3</span> {
    <span class="hljs-attribute">text-transform</span>: uppercase;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
}
<span class="hljs-comment">/* END Componenet */</span>
* {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">body</span>{
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Raleway'</span>, Arial, Helvetica, sans-serif;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">116.82deg</span>, #<span class="hljs-number">3</span>D5467 <span class="hljs-number">0%</span>, #<span class="hljs-number">1</span>A232B <span class="hljs-number">99.99%</span>, #<span class="hljs-number">333333</span> <span class="hljs-number">100%</span>);

}
<span class="hljs-selector-tag">a</span> {
 <span class="hljs-attribute">text-decoration</span>: none;   
}

<span class="hljs-comment">/* Home Page */</span>
<span class="hljs-selector-tag">main</span><span class="hljs-selector-id">#home</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    <span class="hljs-attribute">min-height</span>: <span class="hljs-number">600px</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
}
<span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> {
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</span>;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5rem</span>;
}
<span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">36px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;
}
<span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h3</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">28px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;

}
<span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> &gt; <span class="hljs-selector-tag">h3</span>  {
    <span class="hljs-attribute">font-style</span>: normal;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">42px</span>;
    <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">0.115em</span>;

}
<span class="hljs-selector-id">#home</span> &gt; <span class="hljs-selector-class">.about__me</span> <span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">22px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
}
<span class="hljs-selector-class">.skills_projects_link</span> {
    <span class="hljs-attribute">position</span>: relative;
}
<span class="hljs-selector-class">.skills_projects_link</span> &gt; <span class="hljs-selector-tag">a</span> {
    <span class="hljs-attribute">text-transform</span>: uppercase;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">21px</span>;

}
<span class="hljs-selector-class">.skills_projects_link</span> &gt; <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;
    <span class="hljs-attribute">transition</span>: all <span class="hljs-number">0.5s</span> ease-in-out;

}
<span class="hljs-selector-class">.skills_projects_link</span> &gt; <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span><span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">50%</span>);
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">margin</span>: auto;
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">30px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">2px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#DB5461</span>;
    <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.5s</span> ease-in-out;

}

<span class="hljs-comment">/* Header */</span>
<span class="hljs-selector-id">#site_header</span> {
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">0</span>;
    <span class="hljs-attribute">justify-content</span>: space-between;
    <span class="hljs-attribute">align-items</span>: center;
}
<span class="hljs-selector-id">#site_header</span> &gt; <span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">text-transform</span>: uppercase;
}
<span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span> {
        <span class="hljs-attribute">color</span>: <span class="hljs-number">#e2e2e2</span>;
    <span class="hljs-attribute">text-transform</span>: uppercase;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">900</span>;
}
<span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#DB5461</span>;
}
<span class="hljs-comment">/* Portfolio Page Section */</span>

<span class="hljs-selector-id">#portfolio</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">4rem</span>;

}


<span class="hljs-selector-id">#portfolio</span> <span class="hljs-selector-class">.projects</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-wrap</span>: wrap;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">justify-content</span>: space-around;
}
<span class="hljs-comment">/* Skills */</span>

<span class="hljs-selector-id">#skills_section</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">4rem</span>;
    <span class="hljs-attribute">min-height</span>: <span class="hljs-number">300px</span>;
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(../img/skills_bg.svg);
    <span class="hljs-attribute">background-repeat</span>: no-repeat;
    <span class="hljs-attribute">background-size</span>: contain;
    <span class="hljs-attribute">background-position</span>: top left;
}
<span class="hljs-selector-id">#skills_section</span> <span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">180px</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">44px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#F1EDEE</span>;
    <span class="hljs-attribute">line-height</span>: <span class="hljs-number">2rem</span>;

}
<span class="hljs-selector-id">#skills_section</span> <span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">list-style</span>: none;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span> <span class="hljs-number">120px</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-wrap</span>: wrap;

}
<span class="hljs-selector-id">#skills_section</span> <span class="hljs-selector-tag">ul</span>  <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#DB5461</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid <span class="hljs-number">#3D5467</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">35px</span>;
}



<span class="hljs-selector-class">.avatar</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">30px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">30px</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1rem</span>;

}


<span class="hljs-selector-class">.card__back</span> {
    <span class="hljs-attribute">display</span>: none;
}
<span class="hljs-selector-class">.rotate__card</span> {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate3d</span>(<span class="hljs-number">360</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">180deg</span>);
}
<span class="hljs-comment">/* Site Footer */</span>

<span class="hljs-selector-tag">footer</span> {
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">0</span>;
}



<span class="hljs-comment">/* Media Query  */</span>

<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">475px</span>) {
    <span class="hljs-selector-class">.card</span> {
        <span class="hljs-attribute">flex-basis</span>: <span class="hljs-number">100%</span>;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    }
}
</code></pre>
<p>That's it! We are ready to deply our code to production.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/I6hQnWQU4rQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-continuos-deployment-with-bitbucket-and-netlify">Continuos Deployment with BitBucket and Netlify</h2>
<p>The final step is to deploy our projects so that others can see them. To do that we will use two services:</p>
<ul>
<li>BitBucket, a git-based source code repository for hosting (you can use GitHub if you prefer)</li>
<li>Netlify, a web hosting company that provides hosting for websites that have source code files stored in a Git version control system.</li>
</ul>
<p>You can watch this final video on <a target="_blank" href="https://youtu.be/BH5I68DzcYQ">YouTube here</a>.</p>
<p>You can also checkout the final repositories on BitBucket: </p>
<ul>
<li><a target="_blank" href="https://bitbucket.org/fbhood/simple-twitter/src/master/">SimpleTwitter</a></li>
<li><a target="_blank" href="https://bitbucket.org/fbhood/vue-folio/src">VuePortfolio</a></li>
</ul>
<h3 id="heading-create-the-project-folders-and-copy-all-files">Create the project folders and copy all files</h3>
<p>First, create two folders – one for each project:</p>
<ul>
<li>vue-folio</li>
<li>simple-twitter
then copy all projects files in the related folder.</li>
</ul>
<h3 id="heading-initialize-a-git-repository">Initialize a git repository</h3>
<p>Next, we need to initialise the git repository locally.</p>
<pre><code>cd vue-folio 
git init
git add .
git commit -m<span class="hljs-string">"Initial Commit"</span>
</code></pre><p>You need to execute the commands above in a termial, so you need to have git installed on you system. If you don't, you can read about how to do that <a target="_blank" href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">here</a>.</p>
<p>With the first command, we navigate to the project folder called <code>vue-folio</code>. Then we initialise a git repository, add all files to the staging area, and commit the files.</p>
<p>Repeat the steps above for both projects folders.</p>
<h3 id="heading-create-a-bitbucket-or-github-repository">Create a BitBucket or GitHub repository</h3>
<p>I assume you already have an account with GitHub o BitBucket. But if you don't, then go over and create one.</p>
<p>Follow the steps in the video to create the repositories and connect them with you local repositories.</p>
<h3 id="heading-create-an-account-with-netlify-and-create-a-site">Create an account with Netlify and create a site</h3>
<p>You can use Netlify's free plan for private projects, hobby websites, and experiments. It's a perfect fit for our tutorial. </p>
<p>Follow the steps in the video to deploy your projects there.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/BH5I68DzcYQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-whats-next">What's Next?</h2>
<p>In an upcoming tutorial I'll show you also how to test your code, upgrade to Vue3, and more.</p>
<h3 id="heading-thank-you-for-reading">Thank you for reading!</h3>
<p>I hope you enjoyed this tutorial and the accompanying videos. If so, please share the article and hit the like button on the videos. You can also enable notifications by clicking on the bell icon to know when my next video is online. </p>
<p>If you have any questions please just reach out to me. I reply to all YouTube comments. </p>
<p>Dont forget to subscribe to my YouTube Channel <a target="_blank" href="https://youtube.com/channel/UCTuFYi0pTsR9tOaO4qjV_pQ">here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Fetch Data in React from a GraphQL API ]]>
                </title>
                <description>
                    <![CDATA[ Let's go through the five best ways that you can fetch data with React from a GraphQL API. While there are a couple of popular libraries which are made to interact with GraphQL APIs from a React application, there are many different ways to fetch dat... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/5-ways-to-fetch-data-react-graphql/</link>
                <guid isPermaLink="false">66d0374accf811d3117aeedb</guid>
                
                    <category>
                        <![CDATA[ apollo client ]]>
                    </category>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Reed ]]>
                </dc:creator>
                <pubDate>Mon, 03 May 2021 17:20:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/05/5-ways-to-fetch-data-in-react-with-graphql-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Let's go through the five best ways that you can fetch data with React from a GraphQL API.</p>
<p>While there are a couple of popular libraries which are made to interact with GraphQL APIs from a React application, there are many different ways to fetch data with GraphQL.</p>
<p>I've included code samples that show you how to fetch or "query" data in the shortest code possible and how to get up and running with each of these different methods of connecting React with GraphQL. </p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>In these examples, we'll be using the SpaceX GraphQL API to fetch and display the past 10 missions that SpaceX has made. </p>
<p>Feel free to use the code below if you are attempting to connect your React app with a GraphQL API. In these examples, we're going to go from the most advanced GraphQL client library for React to the simplest approach to querying a GraphQL endpoint. </p>
<h2 id="heading-1-apollo-client">1. Apollo Client</h2>
<p>The most popular and comprehensive GraphQL library is Apollo Client. </p>
<p>Not only can you use it to fetch remote data with GraphQL, which we're doing here, but it allows us to manage data locally, both through an internal cache as well as an entire state management API. </p>
<p>To get started with Apollo Client, you need to install both the main Apollo Client dependency, as well as GraphQL:</p>
<pre><code class="lang-bash">npm install @apollo/client graphql
</code></pre>
<p>The idea behind the Apollo Client is that it will be used across your entire application. To do this, you'll use a special Apollo Provider component to pass a created Apollo client down your entire component tree.</p>
<p>When you create your Apollo Client, you need to specify a <code>uri</code> value, namely a GraphQL endpoint. Additionally, you need to specify a cache. </p>
<p>Apollo Client comes with its own in memory cache, which is used to cache or locally store and manage your queries and their related data:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> { ApolloProvider, ApolloClient, InMemoryCache } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;

<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  <span class="hljs-attr">uri</span>: <span class="hljs-string">"https://api.spacex.land/graphql/"</span>,
  <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache()
});

<span class="hljs-keyword">const</span> rootElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>);
ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span></span>,
  rootElement
);
</code></pre>
<p>Once you've set up the Provider and client within your App component, you can use all of the different React hooks that Apollo Client gives you for all the different GraphQL operations. These include queries, mutations, and subscriptions. You can even use the created Apollo Client directly using a custom hook called <code>useApolloClient</code>. </p>
<p>Since you're just querying data here, you will use the <code>useQuery</code> hook. </p>
<p>You will include a GraphQL query as its first argument to write your query. You'll use the function <code>gql</code>, which does a number of things, such as giving you editor syntax highlighting and the auto formatting functionality if you use the tool Prettier for your project. </p>
<p>Once you execute this query, you get back the values <code>data</code>, <code>loading</code>, and <code>error</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useQuery, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"@apollo/client"</span>;

<span class="hljs-keyword">const</span> FILMS_QUERY = gql<span class="hljs-string">`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, loading, error } = useQuery(FILMS_QUERY);

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="hljs-string">"Loading..."</span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pre</span>&gt;</span>{error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span></span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>SpaceX Launches<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {data.launchesPast.map((launch) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{launch.id}</span>&gt;</span>{launch.mission_name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p> Before you display your data, your missions, you want to handle the loading state. When you are in a loading state, you are fetching the query from a remote endpoint. </p>
<p>You also want to handle any errors that occur. You can simulate an error by making a syntax error in your query, such as querying for a field that doesn't exist. To handle that error, you can conveniently return and display a message from <code>error.message</code>.</p>
<h2 id="heading-2-urql">2. Urql</h2>
<p>Another fully-featured library that connects React apps with GraphQL APIs is urql.</p>
<p>It attempts to give you many of the features and syntax Apollo has while being a little bit smaller in size and requiring less setup code. It gives you caching capabilities if you choose, but it does not include an integrated state management library like Apollo does.</p>
<p>To use urql as your GraphQL client library, you'll need to install the packages urql and GraphQL. </p>
<pre><code class="lang-bash">npm install urql graphql
</code></pre>
<p>Just like Apollo, you'll want to use the dedicated Provider component, and create a client with your GraphQL endpoint. Note that you do not need to specify a cache out of the box.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;
<span class="hljs-keyword">import</span> { createClient, Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'urql'</span>;

<span class="hljs-keyword">const</span> client = createClient({
  <span class="hljs-attr">url</span>: <span class="hljs-string">'https://api.spacex.land/graphql/'</span>,
});

<span class="hljs-keyword">const</span> rootElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>);
ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{client}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>,
  rootElement
);
</code></pre>
<p>Very similar to Apollo, urql gives you custom hooks that handle all the standard GraphQL operations, and therefore have similar names.</p>
<p>Again, you can use the <code>useQuery</code> hook from the urql package. Although instead of needing the function <code>gql</code>, you can drop it and just use a template literal to write your query. </p>
<p>When calling <code>useQuery</code>, you get back an array which you can destructure as an array instead of as an object. The first element in this array is an object, called <code>result</code>, which gives you a number of properties that you can destructure: <code>data</code>, <code>fetching</code>, and <code>error</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'urql'</span>;

<span class="hljs-keyword">const</span> FILMS_QUERY = <span class="hljs-string">`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [result] = useQuery({
    <span class="hljs-attr">query</span>: FILMS_QUERY,
  });

  <span class="hljs-keyword">const</span> { data, fetching, error } = result;

  <span class="hljs-keyword">if</span> (fetching) <span class="hljs-keyword">return</span> <span class="hljs-string">"Loading..."</span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pre</span>&gt;</span>{error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span></span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>SpaceX Launches<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {data.launchesPast.map((launch) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{launch.id}</span>&gt;</span>{launch.mission_name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In an identical fashion to displaying the data that you fetch with Apollo, you can handle both your error and loading states while you're fetching your remote data.</p>
<h2 id="heading-3-react-query-graphql-request">3. React Query + GraphQL Request</h2>
<p>It's important to note at this point that you don't need a sophisticated, heavyweight GraphQL client library like urql or Apollo to interact with your GraphQL API, as we will see later. </p>
<p>Libraries like Apollo and urql were created not only to help you perform all the standard GraphQL operations, but to better manage the server state in your React client through a number of additional tools. All this along with the fact that they come with custom hooks that make managing repetitive tasks like handling loading, error, and other related states simple. </p>
<p>With that in mind, let's take a look at how you can use a very pared-down GraphQL library for your data fetching and combine that with a better means of managing and caching that server state that you're bringing into your application. You can fetch data very simply with the help of the package <code>graphql-request</code>. </p>
<p>GraphQL Request is a library that doesn't require you to set up a client or a Provider component. It is essentially a function that just accepts an endpoint and a query. Very similar to an HTTP client, you just have to pass in those two values and you get back your data. </p>
<p>Now if you want to manage that state across your app, you can use a great library normally used for interacting with Rest APIs – but it's equally helpful for GraphQL APIs – and that is React Query. It gives you some very similarly named React Hooks, <code>useQuery</code> and <code>useMutation</code>, that perform identical tasks to what the Apollo and urql hooks perform. </p>
<p>React Query also gives you a bunch of tools for managing state, along with an integrated Dev Tools component that allows you to see what's being stored in React Query's built-in cache. </p>
<blockquote>
<p>By pairing your very basic GraphQL client, GraphQL request, with React Query you get all the power of a library like urql or Apollo. </p>
</blockquote>
<p>To get started with this pairing, you just need to install React Query and GraphQL Request: </p>
<pre><code class="lang-bash">npm install react-query graphql-request
</code></pre>
<p>You use React Query's Provider component and create a query client where you can set some default data fetching settings if you like. Then within your app component itself, or any child components of <code>App</code>, you can use the <code>useQuery</code> hook. </p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;
<span class="hljs-keyword">import</span> { QueryClient, QueryClientProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-query"</span>;

<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> QueryClient();

<span class="hljs-keyword">const</span> rootElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>);
ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">QueryClientProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">QueryClientProvider</span>&gt;</span></span>,
  rootElement
);
</code></pre>
<p>To store the result of your operation in the React Query cache, you just need to give it a key value as the first argument to serve as an identifier. This allows you to very easily reference and pull data from the cache, as well as to refetch or invalidate a given query to fetch updated data.</p>
<p>Since you're fetching launch data, let's call this query "launches". </p>
<p>Once again, this hook will return the result of making that request. For the second argument to <code>useQuery</code>, you need to specify how to fetch that data and React Query will take care of resolving the promise that GraphQL request returns. </p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { request, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"graphql-request"</span>;
<span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-query"</span>;

<span class="hljs-keyword">const</span> endpoint = <span class="hljs-string">"https://api.spacex.land/graphql/"</span>;
<span class="hljs-keyword">const</span> FILMS_QUERY = gql<span class="hljs-string">`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, isLoading, error } = useQuery(<span class="hljs-string">"launches"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> request(endpoint, FILMS_QUERY);
  });

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="hljs-string">"Loading..."</span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pre</span>&gt;</span>{error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>SpaceX Launches<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {data.launchesPast.map((launch) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{launch.id}</span>&gt;</span>{launch.mission_name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Similar to Apollo, you get back an object that you can destructure to get the values for the data, as well as whether or not you're in the loading state, and the error state.</p>
<h2 id="heading-4-react-query-axios">4. React Query + Axios</h2>
<p>You can use even simpler HTTP client libraries that have no relationship to GraphQL to fetch your data. </p>
<p>In this case, you can use the popular library axios. Once again you can pair it with React Query to get all the special hooks and state management.</p>
<pre><code class="lang-bash">npm install react-query axios
</code></pre>
<p>Using an HTTP client like Axios to perform a query from a GraphQL API requires performing a POST request to your API endpoint. For the data that you send along in the request, you will provide an object with a property called <code>query</code>, which will be set to your films query. </p>
<p>With axios, you're going to need to include a little bit more information about how to resolve this promise and get back your data. You need to tell React Query where the data is so it can be put on the <code>data</code> property that <code>useQuery</code> returns.</p>
<p>In particular, you get the data back on the data property of <code>response.data</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-query"</span>;

<span class="hljs-keyword">const</span> endpoint = <span class="hljs-string">"https://api.spacex.land/graphql/"</span>;
<span class="hljs-keyword">const</span> FILMS_QUERY = <span class="hljs-string">`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, isLoading, error } = useQuery(<span class="hljs-string">"launches"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> axios({
      <span class="hljs-attr">url</span>: endpoint,
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">query</span>: FILMS_QUERY
      }
    }).then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.data.data);
  });

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="hljs-string">"Loading..."</span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pre</span>&gt;</span>{error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>SpaceX Launches<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {data.launchesPast.map((launch) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{launch.id}</span>&gt;</span>{launch.mission_name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<h2 id="heading-5-react-query-fetch-api">5. React Query + Fetch API</h2>
<p>The easiest way of all these different approaches to fetch data is to just use React query plus the fetch API. </p>
<p>Since the fetch API is included in all modern browsers, you do not need to install a third-party library – you only need to install <code>react-query</code> within your application. </p>
<pre><code class="lang-bash">npm install react-query
</code></pre>
<p>Once you have the React Query client provided to the entire app, you can just swap out your axios code with fetch. </p>
<p>What's a little bit different is that you need to specify a header that includes the content type of the data that you want back from your request. In this case, it is JSON data. </p>
<p>You also need to stringify the object that you're sending as your payload with a query property that is set to your films query:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-query"</span>;

<span class="hljs-keyword">const</span> endpoint = <span class="hljs-string">"https://api.spacex.land/graphql/"</span>;
<span class="hljs-keyword">const</span> FILMS_QUERY = <span class="hljs-string">`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, isLoading, error } = useQuery(<span class="hljs-string">"launches"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> fetch(endpoint, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">query</span>: FILMS_QUERY })
    })
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (response.status &gt;= <span class="hljs-number">400</span>) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Error fetching data"</span>);
        } <span class="hljs-keyword">else</span> {
          <span class="hljs-keyword">return</span> response.json();
        }
      })
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> data.data);
  });

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="hljs-string">"Loading..."</span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">pre</span>&gt;</span>{error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>SpaceX Launches<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {data.launchesPast.map((launch) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{launch.id}</span>&gt;</span>{launch.mission_name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>One benefit of using axios over fetch is that it automatically handles errors for you. With fetch, as you can see in the code above, you need to check for a certain status code, in particular a status code above 400. </p>
<p>This means that your request resolves to an error. If that's the case, you need to manually throw an error, which will be caught by your <code>useQuery</code> hook. Otherwise, if it's a 200 or 300 range response, meaning the request was successful, simply return the JSON data and display it.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article was dedicated to showing you a number of different approaches to effectively fetching data from a GraphQL API with React.  </p>
<p>From these options, hopefully you can evaluate which is most appropriate for you and your applications. And now you have some helpful code that will enable you to start using these tools and libraries much faster.</p>
<h2 id="heading-become-a-professional-react-developer">Become a Professional React Developer</h2>
<p>React is hard. You shouldn't have to figure it out yourself.</p>
<p>I've put everything I know about React into a single course, to help you reach your goals in record time:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><strong>Introducing: The React Bootcamp</strong></a></p>
<p><strong>It’s the one course I wish I had when I started learning React.</strong></p>
<p>Click below to try the React Bootcamp for yourself:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/reactbootcamp/react-bootcamp-cta-alt.png" alt="Click to join the React Bootcamp" width="600" height="400" loading="lazy"></a>
<em>Click to get started</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The easiest way to set up server-side rendering with React and axios ]]>
                </title>
                <description>
                    <![CDATA[ By Simone Busoli Server-side rendering (SSR) is a double-edged sword. It’s terribly important for certain applications that require SEO support and meeting certain performance requirements, but it’s nasty to implement properly. Some of the major diff... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-easiest-ssr-with-react-and-axios-f36ed9392a8c/</link>
                <guid isPermaLink="false">66c361419539e75f2cc24a3e</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 19 Feb 2019 11:38:22 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*xHyQy7jPsssJTQaWcrgc3A.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Simone Busoli</p>
<p>Server-side rendering (SSR) is a double-edged sword. It’s terribly important for certain applications that require SEO support and meeting certain performance requirements, but it’s nasty to implement properly.</p>
<p>Some of the major difficulties revolve around user authentication and data pre-loading, especially because there are no established patterns around these.</p>
<p>When building a SPA, often you would use JWT for user authentication, sent via HTTP headers to the server. For data loading instead, you may use React component hooks like <code>componentWillMount</code>. But none of these work when rendering your component tree on the server.</p>
<h4 id="heading-the-idea">? The idea</h4>
<p>You may have heard that not so long ago React introduced support for a new feature called <a target="_blank" href="https://reactjs.org/blog/2019/02/06/react-v16.8.0.html">hooks</a>. This is particularly interesting because hooks are executed whenever the component renders, which opens up a scenario that wasn’t possible until now.</p>
<p>If hooks are executed when the component which uses them is rendered, it means that they’re executed both when rendering on the client and on the server. As a consequence of this, if a hook does an HTTP request and the library we use for doing that works both on the client and on the server, it means that we get HTTP requests on the client and on the server for free! ?</p>
<p><a target="_blank" href="https://github.com/axios/axios">axios</a> is one such library, besides being my favorite one.</p>
<h4 id="heading-the-implementation">⚙️ The implementation</h4>
<p>It turns out that the idea has a reasonably straightforward implementation.</p>
<p>Let’s assume that you have already implemented Server Side Rendering in your React application.</p>
<blockquote>
<p>If you haven’t done so already, there are plenty of tutorials and examples out there. My favorite is found in the Redux <a target="_blank" href="https://redux.js.org/recipes/server-rendering">documentation</a>.</p>
</blockquote>
<p>Let’s assume we now create a hook called <code>useAxios</code>. In its simplest form, it would look something like this:</p>
<p>If you’ve used hooks this shouldn’t look too complicated.</p>
<p>We’re using a <code>React.useState</code> hook to keep the value of the axios response, and a <code>React.useEffect</code> hook to trigger the axios request.</p>
<p>Using this hook would be as simple as this:</p>
<p>If you think this is cool, wait until you figure out - like I did - that this approach makes it super easy to implement data loading during Server Side Rendering.</p>
<p>If you think about it, what’s the complexity involved in pre-loading data on the server?</p>
<p>All that is involved is:</p>
<ul>
<li>triggering HTTP requests</li>
<li>waiting for responses</li>
<li>sending the data to the client along with the generated markup</li>
<li>make the client load the data so that it won’t execute those HTTP requests again, but simply bind the data to the components that need it</li>
</ul>
<p>Now, even though the concept is simple, it requires a bit of coding, hence why I built a library which encapsulated all this logic. It’s basically an extension to the simple implementation seen above, but rather than a dozen lines of code it’s ~100. Considering the features it provides and that using it is still pretty much a one-liner, I find it very exciting!</p>
<h4 id="heading-building-axios-hooks">? Building axios-hooks</h4>
<p>You can check out the code already. The library is called <a target="_blank" href="https://github.com/simoneb/axios-hooks/">axios-hooks</a> and you can install it with:</p>
<p><code>npm install axios-hooks</code></p>
<p>You will find several examples in the documentation, with accompanying <code>codesandbox.io</code> demos to get you started quickly. The usage is very simple but what I’m more interested in explaining is how it works, especially because it’s something that can be applied to many other hooks.</p>
<p>Using it on the client is already useful, because it takes away the pain of using React lifecycle hooks and component state. That’s unless you use a higher-order state management library, in which case you’re probably solving this problem in a different way altogether.</p>
<p>The biggest benefit, though, is combining it with Server Side Rendering. Here’s how it works:</p>
<ol>
<li>The server renders the component tree, i.e. via the <code>renderToString</code> function of the <code>react-dom/server</code> package</li>
<li><code>useAxios</code> hooks are triggered and HTTP requests started</li>
<li><code>axios-hooks</code> keeps a list of all the requests and caches the responses as they come back</li>
<li>The server code awaits for those requests to complete and extracts a serializable representation of them, which can be rendered along with the markup generated by rendering the component tree. This is sent back to the client</li>
<li>The client, before hydrating the component tree, fills the <code>axios-hooks</code> cache with the data returned by the server</li>
<li>The client hydrates the component tree and <code>useAxios</code> hooks are triggered again. Because the data is already there, no actual HTTP request is made on the client</li>
</ol>
<p>The concept is astonishingly simple, as is the implementation.</p>
<p>Checkout ? a<code>[xios-hooks](https://github.com/simoneb/axios-hooks/)</code> today and post your feedback!</p>
<h4 id="heading-credits">Credits</h4>
<p>Credits for the original idea of leveraging React hooks in Server Side Rendering scenarios go to the cool guys at <a target="_blank" href="https://www.nearform.com">NearForm</a>, who built the awesome <code>[graphql-hooks](https://github.com/nearform/graphql-hooks)</code> library.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
