<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Mònade Dev Blog]]></title><description><![CDATA[The voice of the developers from Mònade, a digital studio on Lake Iseo's shores featuring a live pet goat.]]></description><link>https://devs.monade.io</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1649161450742/rb4i_nX-Q.png</url><title>Mònade Dev Blog</title><link>https://devs.monade.io</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 10:06:39 GMT</lastBuildDate><atom:link href="https://devs.monade.io/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[12 modern Terminal/CLI tools that will change your terminal]]></title><description><![CDATA[I switched off my last non-unix computer almost fifteen years ago. Since then I jumped from linux distro to linux distro, until my computer became the medium through which I was working and studying, and I could no longer afford to spend entire night...]]></description><link>https://devs.monade.io/12-modern-terminalcli-tools-that-will-change-your-terminal</link><guid isPermaLink="true">https://devs.monade.io/12-modern-terminalcli-tools-that-will-change-your-terminal</guid><category><![CDATA[terminal]]></category><category><![CDATA[cli]]></category><category><![CDATA[tools]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Fabrizio Mele]]></dc:creator><pubDate>Fri, 18 Nov 2022 11:38:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/4Mw7nkQDByk/upload/v1668430915057/xIYN4XZsb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I switched off my last non-unix computer almost fifteen years ago. Since then I jumped from linux distro to linux distro, until my computer became the medium through which I was working and studying, and I could no longer afford to spend entire nights to trying to <code>pacman -Syu</code> or to fix yet another random error caused by god-only-knows-what. So I entered the magic world of Macs.</p>
<p>Surely the best thing about Macs is that they are UNIX. Yes macOS tends to be user friendly, and to hide almost all of the complexity behind glossy settings panel, but to a power user that knows how to use a terminal (or how to google) the customisation possibilities are surprisingly wide.</p>
<p>All of this to say that macOS is my daily driver, and as a developer I spend much of my day inside a terminal. In the last few years I created what I consider the most ergonomic terminal experience I ever had, much thanks to modern tools and commands which replace or encapsulate good 'ole programs, like <code>cat</code> , <code>curl</code> or <code>find</code>. My coworkers, after months of me bugging them about this stuff, found this a perfect subject on which to write a curated list! So, here they come.</p>
<h2 id="heading-modern-replacements">Modern replacements</h2>
<p>This tools are meant to replace existing common commands, sometimes as a drop in that requires just an alias in your dotfile.</p>
<h4 id="heading-lsd">lsd</h4>
<p><code>lsd</code> is a replacement for ls which introduces fancy colors and icons, while also being very configurable. It can be installed through almost any package manager, including Homebrew.</p>
<p>To set it as the "new" ls command just drop <code>alias ls="lsd"</code> in your terminal dotfile. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770163378/ahHdEY5Tm.png" alt="lsd in action" /></p>
<h4 id="heading-bat">bat</h4>
<p><code>bat</code> is another really pretty tool , which is a drop-in for <code>cat</code> (a cat clone with wings). Bat supports syntax coloring, line numbers and git status, and can be configured via environment variables. </p>
<p>I've set <code>alias cat="bat -P"</code> in my config.fish and this is the result:</p>
<p>To remove line numbers just set <code>alias ccat="bat -Pp"</code> or something similar. Bat is available in all package managers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770205790/8nt-3c2YY.png" alt="bat in action" /></p>
<h4 id="heading-zoxide-and-fzf">zoxide and fzf</h4>
<p>One of the most tedious things to do while working in a terminal is getting around directories and jumping back and forth between them. <a target="_blank" href="https://github.com/ajeetdsouza/zoxide">Zoxide</a> comes to our rescue, and paired with <code>fzf</code>, the command-line fuzzy finder, it could well remove almost entirely <code>cd</code> from your command history.</p>
<p>I recommend you go and take a look at all the usages and installation steps <a target="_blank" href="https://github.com/ajeetdsouza/zoxide">on Github</a>.</p>
<p><code>z</code> could easily replace the cd command, by being smarter and almost magical in its way to determine to which directory you want to navigate to (<a target="_blank" href="https://github.com/junegunn/fzf#installation">but you will need fzf for this</a>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770286495/d0eGODHhZ.png" alt="1_yqpGtejyImZfAAmOaZ-3MA@2x.png" /></p>
<h4 id="heading-mcfly">mcfly</h4>
<p><code>mcfly</code> is a nice little utility that replaces the ctrl+r behaviour of your shell with a search engine powered by a small neural network. I don't often use the ctrl+r , but when I do mcfly saves much much time and effort.
Installation and configuration instructions can be found <a target="_blank" href="https://github.com/cantino/mcfly">at the Github repo</a>, I will just drop here a screenshot of its workings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770301935/35wDq8gFf.png" alt="1_ImVXgC7v8PQ5-hNeTkJC1g@2x.png" /></p>
<h4 id="heading-the-silver-searcher">The Silver Searcher</h4>
<p><a target="_blank" href="https://github.com/ggreer/the_silver_searcher">The Silver Searcher</a>, aka ag , is a powerful (and fast!) code searching tool that saves me much time for example when I need to edit something inside some file in the current directory. It respects by default your ignore files, and has some handy options to filter the files. Install it with the package the_silver_searcher and try it out.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770325342/Ls7sjDxOb.png" alt="1_4Dsf8Zld75ERvjXFoi0aWg@2x.png" /></p>
<p>All the .ts files that contain "ArticleCardComponent", executed in 30ms. Needless to say this is much much faster than any find and grep combo.</p>
<p><a target="_blank" href="https://github.com/BurntSushi/ripgrep">ripgrep</a> is a very similar tool, but I like ag more.</p>
<h4 id="heading-curlie">curlie</h4>
<p><a target="_blank" href="https://github.com/rs/curlie">Curlie</a> is a really nice drop-in replacement for curl. Curl is all powerful and almighty, but curlie takes it a step further mantaining parameter compatibility with the former.
It supports syntax highlighting for headers and content, and prettifies json output when running interactively. 
<code>alias curl=curlie</code> is really a no brainer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770379846/Pf4FFvxEn.png" alt="1_LqmpdhOR4GQicGffEeccwA.png" /></p>
<h4 id="heading-jq">jq</h4>
<p>jq is an essential tool to slice, filter, map and transform json data in command pipes. 
To get a sense on what it can do take a look <a target="_blank" href="https://stedolan.github.io/jq/">here</a>. It is a life saver while working on apis via curl.</p>
<h4 id="heading-fx">fx</h4>
<p><a target="_blank" href="https://github.com/antonmedv/fx">fx</a> is <code>less</code> but for json, and smart. It is super useful to explore long json files or outputs, and requires zero learning time to get proficient with it.
It accepts files as arguments or piped input, like less, and has mouse support.</p>
<p><img src="https://i.imgur.com/hlsHLcI.gif" alt="fx" /></p>
<h2 id="heading-tui-tools">TUI tools</h2>
<p>These are tools which use a terminal user interface to make things faster and I definitely use them very often.</p>
<h4 id="heading-lazygit">lazygit</h4>
<p>If I ever hosted "CLI Program of The Year" award then <a target="_blank" href="https://github.com/jesseduffield/lazygit">lazygit</a> would win. I'm not a git cli expert, I've always used GUIs because I'm lazy and I like having a graphical representation of the status of my repos. I started with SourceTree years ago, then moved to GitKraken when SourceTree started to require a full minute to commit a handful of files, then moved to Tower when I felt the need for a native app.</p>
<blockquote>
<p>If you're a mere mortal like me and you're tired of hearing how powerful git is when in your daily life it's a powerful pain in your ass, lazygit might be for you. (<em>lazygit author jesseduffield</em>)</p>
</blockquote>
<p>Then I gave a try at lazygit, and now Tower is only for complicated squashes, rebases and advanced stuff. Lazygit is a wonderful TUI git client, made for speed and convenience: to stage all file just press <code>a</code>, to commit them press <code>c</code>, type your message, and then hit enter. To push <code>P</code> , to pull <code>p</code>, space to checkout a branch. If you ever feel lost x brings up the menu, with all available commands shown together with their shortcut. To give you an idea of the convenience and the ease of use, I tried multiple times to use vim or emacs as an everyday "light" editor, but were never able to get really used to all commands, shortcuts and whatnot. With lazygit everything felt almost as second nature for me.
It's strongly suggested to at least give it a try.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770554293/YbXLkR7Tt.gif" alt="1_ELxEZ3P3xnJuWDC-bNnq5w.gif" /></p>
<h4 id="heading-nnn">nnn</h4>
<p>n³ (recursive acronym of <em>Nnn's Not Noice!</em>) is a nice and fast TUI file manager. It has a ton of features and the author has a strong opinion on how it should be used. It so rich of features that I felt fairly overwhelmed, but this didn't stop me from using its most easy and straightforward features, like simple navigation and quick editing.
<a target="_blank" href="https://github.com/jarun/nnn">Give it a try</a>, it's way faster and handy than the usual ls + cd flow.</p>
<p><img src="https://i.imgur.com/WhjA9f5.gif" alt="1_mOcnErVNXP--tibH4V7KkQ.gif" /></p>
<h4 id="heading-broot">broot</h4>
<p><a target="_blank" href="https://github.com/Canop/broot"><code>broot</code></a> covers similar use cases to nnn , but it is different, and may better appease your personal taste, and is more a "tree replacement"
Like n³ it support searching, paning, and file previews. For instance, it has a much better support for the "cd on exit" action.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770637833/4vKcKi_Nz.png" alt="1_IjdnfgKgP3rf3wHDetieUw.png" /></p>
<h4 id="heading-micro">micro</h4>
<p><a target="_blank" href="https://micro-editor.github.io">Micro</a> is a simple and intuitive text editor, that relies on common conventions (eg. ctrl+s to save, ctrl+q to quit) and useful comforts (scroll and select with the mouse). It supports theming and syntax highlighting, and has some nice plugins, although the ecosystem is quite small.
It is perfect to do edits on the fly, it is the first thing I install on any new system (it ships in a single static binary).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668770647500/CJ1Y3yOtA.png" alt="1_1tIykHk_AbRh_trLGLWYAw.png" /></p>
]]></content:encoded></item><item><title><![CDATA[A Circular Progress Bar made only with <div />]]></title><description><![CDATA[TLDR: If you aren't interested in understanding the mechanincs of this circular progress bar built without using svg or canvas, and the only thing you want is to use this component in your React application, just checkout our npm package.
Working wit...]]></description><link>https://devs.monade.io/a-circular-progress-bar-made-only-with-div</link><guid isPermaLink="true">https://devs.monade.io/a-circular-progress-bar-made-only-with-div</guid><category><![CDATA[React]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Federico Mainetti Gambera]]></dc:creator><pubDate>Wed, 12 Oct 2022 13:00:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401581298/I0BJo3ykh.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TLDR:</strong> If you aren't interested in understanding the mechanincs of this circular progress bar built without using <code>svg</code> or <code>canvas</code>, and the only thing you want is to use this component in your React application, just checkout our <strong><a target="_blank" href="https://www.npmjs.com/package/@monade/react-circular-progress-bar">npm package</a></strong>.</p>
<p>Working with curved elements in HTML is not simple, developers usually find themselves having to use elements like <code>&lt;canvas&gt;</code> or <code>&lt;svg&gt;</code> to accomplish their goals.</p>
<p>For example, an horizontal progress bar is very simple to make in HTML + CSS + JS, however, to make it round, the complexity is much greater.</p>
<p>In this article I'm going to explain how to use only <strong><code>&lt;div/&gt;</code></strong> elements and some clever <strong>CSS</strong> to build a cool <strong>circular progress bar</strong>.</p>
<h2 id="heading-how-does-it-work">How Does It Work?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665400980976/y_h1Bcvhm.gif" alt="final220speed.gif" /></p>
<p>To build a circular progress bar we'll use two important CSS properties:</p>
<ul>
<li><strong><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/clip">Clip</a></strong>: this property allows us to identify a <strong>visibility rectangle</strong> for an element whose position is absolute (es. <code>clip: rect(1px, 10em, 3rem, 2ch);</code>). Any children that is not positioned inside the visibility rectangle will not be rendered.</li>
<li><strong><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform">Transform</a></strong>: this property is very powerful, but we will only use it to <strong>rotate</strong> some elements.</li>
</ul>
<p>The technique I will show you breaks the circle into two halves, the one on the right (from 0% to 50%) and the one on the left (from 50% to 100%).
To better understand how we can achive this goal, we'll initially analize
To understand more easily how it works, initially we'll analyze only the right half, and, for the left half, we'll just need to apply the same reasoning but mirrored.</p>
<p>So, for the first half of the circle there are two main elements:</p>
<ul>
<li>a square <strong>container</strong> <code>div</code>, that contains...</li>
<li>...the actual full <strong>circle</strong> <code>div</code>.</li>
</ul>
<p>The container height and width are the same as the circle's ones, like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401083385/Vb6DCkucm.png" alt="screen00.png" /></p>
<p>With the <strong>clip</strong> property <strong>applied to the circle</strong> we can hide his right half, obtaining only a left half circle.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401097319/x0zEyNdqq.png" alt="screen01.png" /></p>
<p>With the <strong>clip</strong> property <strong>applied to the container</strong> we can hide anything that is in the left half and only show what is in the right half. Since there is nothing to show in the right half we now have an empty square, that secretly hides half a circle.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401107765/Y3ph_d3AP.png" alt="screen02.png" /></p>
<p>Now, if we slightly rotate the hidden half circle with the <strong>tranform</strong> property, we will see it come out on the right side, like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401119402/XDt-8iAWK.png" alt="screen03.png" /></p>
<p>So, if we want to show some progress, we just need to rotare the half colored circle so that it starts to show in the non-clipped right side.</p>
<p>This process only covers the progress of the right half (from 0% to 50%), but if we apply the same reasoning for the other half and we put some logic behind the rotation, we can achieve the illusion of a circular progress bar.</p>
<h2 id="heading-lets-build-it-with-html-css-and-javascript">Let's build it with HTML, CSS and JavaScript</h2>
<p>Let's put everything we said in practice with a simple and plain HTML, CSS and JavaScript application.</p>
<p>Feel free to follow along step by step, or, if you want to skip to the final solution, you can find all the code that will be used in this section <strong><a target="_blank" href="https://github.com/monade/circular-progress-bar/tree/main/circular-progress-bar-html-css-js">here</a></strong>.</p>
<h3 id="heading-step-1-basic-structure">Step 1: Basic Structure</h3>
<p>The first step we'll take is to get all the elements we need in place:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401144420/uIoltxNij.png" alt="screen1.png" /></p>
<p>Let's start with a simple <code>index.html</code> that contains two main elements:</p>
<ul>
<li>a <strong>slider</strong> to control the percentage of progress and</li>
<li>a <strong>group of <code>&lt;div/&gt;</code> elements</strong> that represent the ciruclar progress bar as explained in the above section.</li>
</ul>
<h5><strong><code>index.html</code></strong></h5>

<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>Circular progress bar<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">type</span>=<span class="hljs-string">"text/css"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./index.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">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">"circular"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"circle"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bar right"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress"</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">"bar left"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress"</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-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">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>0<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"input-range"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"range"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>100<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">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./index.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 better understand what the purpose of each of these <code>&lt;div/&gt;</code> elements is:</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">"bar right"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress"</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">"bar left"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<ul>
<li>The two <code>&lt;div class="progress" /&gt;</code> are the actual <strong>half-circle elements</strong> that correctly rotated will represent the right-half of the circle (from 0% to 50%) and the left-half of the circle (from 50% to 100%).</li>
<li><code>&lt;div class="bar right"&gt;</code> and <code>&lt;div class="bar left"&gt;</code> are the two <strong>containers</strong> we were talking about in the previous section. Their purpose is to use the clip css property to hide and show part of their children elements.</li>
</ul>
<p>Now let's apply some basic css to get everything in place:</p>
<h5><strong><code>index.css</code></strong></h5>

<pre><code class="lang-css"><span class="hljs-comment">/* this css rule is used only to help us with visual debug */</span>
* {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid red;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</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-attribute">padding</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.container</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0px</span> <span class="hljs-number">30px</span>;
}

<span class="hljs-selector-class">.circular</span> {
  <span class="hljs-attribute">position</span>: relative;
  <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-comment">/*
  * Diameter of the circle: 500px, 
  * we'll fix the fact that this value is hardcoded later 
  */</span>
  <span class="hljs-attribute">height</span>: <span class="hljs-number">500px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">500px</span>;
}

<span class="hljs-selector-class">.circular</span> <span class="hljs-selector-class">.bar</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.circle</span> <span class="hljs-selector-class">.bar</span> <span class="hljs-selector-class">.progress</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p>All this css is pretty straight forward, the only things to note are:</p>
<ul>
<li><code>* { border: 1px solid red; }</code> is used only for visual debug purpose</li>
<li>in the <code>.circular { /*...*/ }</code> rule we hardcode the height and the width to match the diamater of the circle of the progress bar we are going to create, but this is only temporary, we'll remove it later.</li>
</ul>
<p>All that is left is some basic JavaScript:</p>
<h5><strong><code>index.js</code></strong></h5>

<pre><code class="lang-js"><span class="hljs-comment">/**
 * Waits for the document to be ready before running the init function
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">docReady</span>(<span class="hljs-params">fn</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">document</span>.readyState === <span class="hljs-string">"complete"</span>
      || <span class="hljs-built_in">document</span>.readyState === <span class="hljs-string">"interactive"</span>) {
    <span class="hljs-built_in">setTimeout</span>(fn, <span class="hljs-number">1</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"DOMContentLoaded"</span>, fn);
  }
}
docReady(init);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// set up will happen here...</span>

  makeProgressBarInteractive();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeProgressBarInteractive</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> inputRef = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"input"</span>)[<span class="hljs-number">0</span>];
  inputRef.addEventListener(<span class="hljs-string">"input"</span>, updateCiruclarProgressBar);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateCiruclarProgressBar</span>(<span class="hljs-params">event</span>) </span>{
  <span class="hljs-built_in">console</span>.log(event.target.value);

  <span class="hljs-comment">// fix the rotation of the circles to match the slider value...</span>
}
</code></pre>
<h3 id="heading-step-2-clip">Step 2: Clip</h3>
<p>The next step is to define a <strong>diameter</strong> in pixels and a <strong>color</strong> for our circles:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> DIAMETER = <span class="hljs-number">500</span>;
<span class="hljs-keyword">const</span> COLOR = <span class="hljs-string">"#ff0000"</span>;
</code></pre>
<p>Now the <code>init</code> function will get the references of all the <code>&lt;div/&gt;</code> elements and set up the <strong>background-color</strong> and the <strong>clip</strong> properties:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> inputRef = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> rightBar = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> leftBar = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> rightProgress = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> leftProgress = <span class="hljs-literal">null</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span>(<span class="hljs-params"></span>) </span>{
  rightBar = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"bar"</span>)[<span class="hljs-number">0</span>];
  leftBar = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"bar"</span>)[<span class="hljs-number">1</span>];
  rightProgress = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"progress"</span>)[<span class="hljs-number">0</span>];
  leftProgress = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"progress"</span>)[<span class="hljs-number">1</span>];

  <span class="hljs-comment">// clip the right part of the circle</span>
  rightBar.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px)`</span>;
  <span class="hljs-comment">// clip the left part of the circle</span>
  rightProgress.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, 0px)`</span>;

  <span class="hljs-comment">// clip the left part of the cicle</span>
  leftBar.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, 0px)`</span>;
  <span class="hljs-comment">// clip the right part of the circle</span>
  leftProgress.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px)`</span>;

  <span class="hljs-comment">// set background color</span>
  rightProgress.style.backgroundColor = <span class="hljs-string">`<span class="hljs-subst">${COLOR}</span>`</span>;
  leftProgress.style.backgroundColor = <span class="hljs-string">`<span class="hljs-subst">${COLOR}</span>`</span>;

  makeProgressBarInteractive();
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401214726/c5V6zoWF3.png" alt="screen2.png" /></p>
<h3 id="heading-step-3-rotate">Step 3: Rotate</h3>
<p>Now the fun part! Let's rotate the <code>rightProgress</code> and <code>leftProgress</code> elements accordingly to the percentage value of the slider.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401241603/qgVeAzsFr.png" alt="screen4.png" /></p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeProgressBarInteractive</span>(<span class="hljs-params"></span>) </span>{
  inputRef = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"input"</span>)[<span class="hljs-number">0</span>];

  inputRef.addEventListener(<span class="hljs-string">"input"</span>, updateCiruclarProgressBar);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateCiruclarProgressBar</span>(<span class="hljs-params">event</span>) </span>{
  <span class="hljs-comment">// percentage value is get from the slider</span>
  <span class="hljs-keyword">const</span> percentage = event.target.value / <span class="hljs-number">100</span>;

  <span class="hljs-comment">// the right side of the circle handles the progress from 0% up to 50%</span>
  <span class="hljs-comment">// if the progress is over 50% then the rotation will max at 180 degrees</span>
  rightProgress.style.transform = <span class="hljs-string">`rotate(<span class="hljs-subst">${percentage &lt; <span class="hljs-number">0.5</span> ? percentage * <span class="hljs-number">2</span> * <span class="hljs-number">180</span> : <span class="hljs-number">180</span>}</span>deg)`</span>;

  <span class="hljs-comment">// the left side of the circle handles the progress from 50% up to 100%</span>
  <span class="hljs-comment">// if the progress is under 50% then the rotation will be of 0 degrees.</span>
  leftProgress.style.transform = <span class="hljs-string">`rotate(<span class="hljs-subst">${percentage &gt; <span class="hljs-number">0.5</span> ? percentage * <span class="hljs-number">2</span> * <span class="hljs-number">180</span> + <span class="hljs-number">180</span> : <span class="hljs-number">0</span>}</span>deg)`</span>;
}
</code></pre>
<p>An important thing to note is that the <code>leftProgress</code> element must start to rotate only when the percentage of progress reaches 50%, on the other side, the <code>rightProgress</code> element must stop his rotation when the percentage of progress reaches 50%.</p>
<h3 id="heading-step-4-polishing-the-details">Step 4: Polishing the details</h3>
<p>To have a beautiful circle all that is left is to get rid of the <code>* { border: 1px solid red; }</code> property:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401262898/3wJZLq2Nv.png" alt="screen5.png" /></p>
<p>We also need to handle with JavaScript the question of the height and width that was initially hardcoded in the css:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.circular</span> {
  <span class="hljs-comment">/*...*/</span>
  <span class="hljs-comment">/* remove -&gt; height: 500px; */</span>
  <span class="hljs-comment">/* remove -&gt; width: 500px; */</span>
}
</code></pre>
<p>and replace it with:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> circularRef = <span class="hljs-literal">null</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span>(<span class="hljs-params"></span>) </span>{
  circularRef = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"circular"</span>)[<span class="hljs-number">0</span>];
  circularRef.style.height = DIAMETER + <span class="hljs-string">"px"</span>;
  circularRef.style.width = DIAMETER + <span class="hljs-string">"px"</span>;

  <span class="hljs-comment">//...</span>
}
</code></pre>
<p>At the end our JavaScript file will look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> DIAMETER = <span class="hljs-number">500</span>;
<span class="hljs-keyword">const</span> COLOR = <span class="hljs-string">"#ff0000"</span>;

<span class="hljs-keyword">let</span> inputRef = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> rightBar = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> leftBar = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> rightProgress = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> leftProgress = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> circularRef = <span class="hljs-literal">null</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeProgressBarInteractive</span>(<span class="hljs-params"></span>) </span>{
  inputRef = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"input"</span>)[<span class="hljs-number">0</span>];

  inputRef.addEventListener(<span class="hljs-string">"input"</span>, updateCiruclarProgressBar);
  inputRef.value = <span class="hljs-number">0</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span>(<span class="hljs-params"></span>) </span>{
  circularRef = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"circular"</span>)[<span class="hljs-number">0</span>];
  circularRef.style.height = DIAMETER + <span class="hljs-string">"px"</span>;
  circularRef.style.width = DIAMETER + <span class="hljs-string">"px"</span>;

  rightBar = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"bar"</span>)[<span class="hljs-number">0</span>];
  leftBar = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"bar"</span>)[<span class="hljs-number">1</span>];
  rightProgress = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"progress"</span>)[<span class="hljs-number">0</span>];
  leftProgress = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"progress"</span>)[<span class="hljs-number">1</span>];

  rightBar.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px)`</span>;
  rightProgress.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, 0px)`</span>;

  leftBar.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, 0px)`</span>;
  leftProgress.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER}</span>px, <span class="hljs-subst">${DIAMETER / <span class="hljs-number">2</span>}</span>px)`</span>;

  rightProgress.style.backgroundColor = <span class="hljs-string">`<span class="hljs-subst">${COLOR}</span>`</span>;
  leftProgress.style.backgroundColor = <span class="hljs-string">`<span class="hljs-subst">${COLOR}</span>`</span>;

  makeProgressBarInteractive();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateCiruclarProgressBar</span>(<span class="hljs-params">event</span>) </span>{
  <span class="hljs-keyword">const</span> percentage = event.target.value / <span class="hljs-number">100</span>;
  rightProgress.style.transform = <span class="hljs-string">`rotate(<span class="hljs-subst">${percentage &lt; <span class="hljs-number">0.5</span> ? percentage * <span class="hljs-number">2</span> * <span class="hljs-number">180</span> : <span class="hljs-number">180</span>}</span>deg)`</span>;
  leftProgress.style.transform = <span class="hljs-string">`rotate(<span class="hljs-subst">${percentage &gt; <span class="hljs-number">0.5</span> ? percentage * <span class="hljs-number">2</span> * <span class="hljs-number">180</span> + <span class="hljs-number">180</span> : <span class="hljs-number">0</span>}</span>deg)`</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">docReady</span>(<span class="hljs-params">fn</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">document</span>.readyState === <span class="hljs-string">"complete"</span> || <span class="hljs-built_in">document</span>.readyState === <span class="hljs-string">"interactive"</span>) {
    <span class="hljs-built_in">setTimeout</span>(fn, <span class="hljs-number">1</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"DOMContentLoaded"</span>, fn);
  }
}
docReady(init);
</code></pre>
<h3 id="heading-step-5-content-inside-the-circle">Step 5: Content inside the circle</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401300524/_tvdz1xUP.png" alt="screen7.png" /></p>
<p>Now that we have a full circle that fills up based on a percentage, the next step would be to put some content inside the circle. I have decided to simply show a slightly smaller circle colored as the background (white) with the percentage written in the center.</p>
<h5><strong><code>index.html</code></strong></h5>

<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- ... --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</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">"circular"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- ... --&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">"content"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>0%<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-comment">&lt;!-- ... --&gt;</span>
</code></pre>
<h5><strong><code>index.css</code></strong></h5>

<pre><code class="lang-css"><span class="hljs-comment">/* ... */</span>

<span class="hljs-selector-class">.content</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1000</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-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<h5><strong><code>index.js</code></strong></h5>

<pre><code class="lang-js"><span class="hljs-keyword">const</span> BORDER_WIDTH = <span class="hljs-number">20</span>;
<span class="hljs-keyword">const</span> BACKGROUND_COLOR = <span class="hljs-string">"#ffffff"</span>;

<span class="hljs-keyword">let</span> content = <span class="hljs-literal">null</span>;

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

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

  content = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"content"</span>)[<span class="hljs-number">0</span>];
  content.style.height = DIAMETER - BORDER_WIDTH + <span class="hljs-string">"px"</span>;
  content.style.width = DIAMETER - BORDER_WIDTH + <span class="hljs-string">"px"</span>;
  content.style.backgroundColor = BACKGROUND_COLOR;

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

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateCiruclarProgressBar</span>(<span class="hljs-params">event</span>) </span>{
  <span class="hljs-comment">// ...</span>

  content.firstElementChild.innerHTML = <span class="hljs-string">`<span class="hljs-subst">${event.target.value}</span>%`</span>;
}
</code></pre>
<p>The final result looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401322374/1v2P-DYF-.gif" alt="final.gif" /></p>
<h2 id="heading-4-lets-make-it-in-react">4. Let's make it in React</h2>
<p>Now that we have a good understangind of the mechanics behind this circular progress bar, let's wrap everything we have said so far in a <strong>React component</strong>.</p>
<p>We want the react component to be <strong>as customizable as possible</strong> throught props like:</p>
<ul>
<li><strong>percentage of progress</strong></li>
<li><strong>diameter</strong></li>
<li><strong>color</strong></li>
<li><strong>border width</strong></li>
<li><strong>content background color</strong></li>
<li><strong>content as a children element</strong></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665401339467/7rTSAE6rJ.gif" alt="final220speed.gif" /></p>
<p><strong>Note</strong>: this component is <strong>typescript friendly</strong>.</p>
<h5><strong><code>circularProgressBar.tsx</code></strong></h5>

<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { MutableRefObject, useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./circularProgressBar.css"</span>;

<span class="hljs-keyword">interface</span> circularProgressBarPropsInterface {
  color: <span class="hljs-built_in">string</span>;
  diameter: <span class="hljs-built_in">number</span>;
  percentage: <span class="hljs-built_in">number</span>;
  borderWidth?: <span class="hljs-built_in">number</span>;
  contentBackgroundColor?: <span class="hljs-built_in">string</span>;
  className?: <span class="hljs-built_in">string</span>;
  contentClassName?: <span class="hljs-built_in">string</span>;
  children?: JSX.Element;
}

<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">CircularProgressBar</span>(<span class="hljs-params">{
  color,
  diameter,
  percentage,
  borderWidth,
  contentBackgroundColor,
  className,
  contentClassName,
  children,
}: circularProgressBarPropsInterface</span>) </span>{
  <span class="hljs-keyword">const</span> rightBar = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>) <span class="hljs-keyword">as</span> MutableRefObject&lt;HTMLDivElement&gt;;
  <span class="hljs-keyword">const</span> rightProgress = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>) <span class="hljs-keyword">as</span> MutableRefObject&lt;HTMLDivElement&gt;;
  <span class="hljs-keyword">const</span> leftBar = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>) <span class="hljs-keyword">as</span> MutableRefObject&lt;HTMLDivElement&gt;;
  <span class="hljs-keyword">const</span> leftProgress = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>) <span class="hljs-keyword">as</span> MutableRefObject&lt;HTMLDivElement&gt;;
  <span class="hljs-keyword">const</span> content = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>) <span class="hljs-keyword">as</span> MutableRefObject&lt;HTMLDivElement&gt;;

  <span class="hljs-comment">// setup dimensions, colors, and clip properties</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (borderWidth) {
      content.current.style.height = diameter - borderWidth + <span class="hljs-string">"px"</span>;
      content.current.style.width = diameter - borderWidth + <span class="hljs-string">"px"</span>;
    }

    <span class="hljs-keyword">if</span> (contentBackgroundColor) {
      content.current.style.backgroundColor = contentBackgroundColor;
    }

    rightBar.current.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${diameter}</span>px, <span class="hljs-subst">${diameter}</span>px, <span class="hljs-subst">${diameter / <span class="hljs-number">2</span>}</span>px)`</span>;
    rightProgress.current.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${diameter / <span class="hljs-number">2</span>}</span>px, <span class="hljs-subst">${diameter}</span>px, 0px)`</span>;

    leftBar.current.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${diameter / <span class="hljs-number">2</span>}</span>px, <span class="hljs-subst">${diameter}</span>px, 0px)`</span>;
    leftProgress.current.style.clip = <span class="hljs-string">`rect(0px, <span class="hljs-subst">${diameter}</span>px, <span class="hljs-subst">${diameter}</span>px, <span class="hljs-subst">${diameter / <span class="hljs-number">2</span>}</span>px)`</span>;

    rightProgress.current.style.backgroundColor = <span class="hljs-string">`<span class="hljs-subst">${color}</span>`</span>;
    leftProgress.current.style.backgroundColor = <span class="hljs-string">`<span class="hljs-subst">${color}</span>`</span>;
  }, [color, diameter, borderWidth, contentBackgroundColor]);

  <span class="hljs-comment">// handles the rotation</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!percentage) {
      rightProgress.current.style.transform = <span class="hljs-string">`rotate(0deg)`</span>;
      leftProgress.current.style.transform = <span class="hljs-string">`rotate(0deg)`</span>;
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">let</span> floatPercentage = percentage / <span class="hljs-number">100</span>;
    rightProgress.current.style.transform = <span class="hljs-string">`rotate(<span class="hljs-subst">${floatPercentage &lt; <span class="hljs-number">0.5</span> ? floatPercentage * <span class="hljs-number">2</span> * <span class="hljs-number">180</span> : <span class="hljs-number">180</span>}</span>deg)`</span>;
    leftProgress.current.style.transform = <span class="hljs-string">`rotate(<span class="hljs-subst">${floatPercentage &gt; <span class="hljs-number">0.5</span> ? floatPercentage * <span class="hljs-number">2</span> * <span class="hljs-number">180</span> + <span class="hljs-number">180</span> : <span class="hljs-number">0</span>}</span>deg)`</span>;
  }, [percentage]);

  <span class="hljs-keyword">return</span> (
    &lt;div className={<span class="hljs-string">`container <span class="hljs-subst">${className ?? <span class="hljs-string">""</span>}</span>`</span>}&gt;
      &lt;div className=<span class="hljs-string">'circular'</span> style={{ height: diameter, width: diameter }}&gt;
        &lt;div className=<span class="hljs-string">'circle'</span>&gt;
          &lt;div className=<span class="hljs-string">'bar right'</span> ref={rightBar}&gt;
            &lt;div className=<span class="hljs-string">'progress'</span> ref={rightProgress} /&gt;
          &lt;/div&gt;
          &lt;div className=<span class="hljs-string">'bar left'</span> ref={leftBar}&gt;
            &lt;div className=<span class="hljs-string">'progress'</span> ref={leftProgress} /&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div className={<span class="hljs-string">`content <span class="hljs-subst">${contentClassName ?? <span class="hljs-string">""</span>}</span>`</span>} ref={content}&gt;
        {children}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<h5><strong><code>circularProgressBar.css</code></strong></h5>

<pre><code class="lang-css"><span class="hljs-selector-class">.container</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-attribute">padding</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.circular</span> {
  <span class="hljs-attribute">position</span>: relative;
  <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-selector-class">.circular</span> <span class="hljs-selector-class">.bar</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.circle</span> <span class="hljs-selector-class">.bar</span> <span class="hljs-selector-class">.progress</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.content</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1000</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-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p>That's it. Now we have a fully customized and reusable circular progress bar that we can easily throw in any of our projects.</p>
<h2 id="heading-npm-package">npm package</h2>
<p>If you want to use this circular progress bar in your React application we have made an <strong><a target="_blank" href="https://link.to.thingy">npm package</a></strong> for you.</p>
<p>First we need to install the package with <strong>npm</strong>:</p>
<pre><code>npm install @monade/react-circular-progress-bar
</code></pre><p>or with <strong>yarn</strong>:</p>
<pre><code>yarn add @monade/react-circular-progress-bar
</code></pre><p>Then we just need to <strong>import</strong> and <strong>use</strong> it like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { CircularProgressBar } <span class="hljs-keyword">from</span> <span class="hljs-string">"@monade/react-circular-progress-bar"</span>;
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">CircularProgressBar</span>
  <span class="hljs-attr">diameter</span>=<span class="hljs-string">"{...}"</span>
  <span class="hljs-attr">color</span>=<span class="hljs-string">"{...}"</span>
  <span class="hljs-attr">percentage</span>=<span class="hljs-string">"{...}"</span>
  <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">"{...}"</span>
  <span class="hljs-attr">contentBackgroundColor</span>=<span class="hljs-string">"{...}"</span>
  <span class="hljs-attr">className</span>=<span class="hljs-string">"{...}"</span>
  <span class="hljs-attr">contentClassName</span>=<span class="hljs-string">"{...}"</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">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">CircularProgressBar</span>&gt;</span>
</code></pre>
<h2 id="heading-an-use-case-hippopods-player">An use case: Hippopod's Player</h2>
<p>My journey through the problem of circular progress bars in web development started when I was working on <strong>Hippopod</strong>, an open source project that takes an RSS feed and transform it in a static podcast websites.</p>
<p>During the development I found myself having to develop an audio player, whose play / pause button component had to take care of showing the progress of the track being played like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665400912824/_VbrP6MjE.png" alt="hippopod-player.png" /></p>
<p>If you are interested in what Hippopod is, check it out at <strong><a target="_blank" href="https://hippopod.xyz/">hippopod.xyz</a></strong></p>
]]></content:encoded></item><item><title><![CDATA[Speed up rendering in your Angular application]]></title><description><![CDATA[After working with Angular for quite some time, I have come to love how you can build modular, scalable applications.
The road to using this framework effectively can be quite a bumpy one though, or at least I know it was for me! As stakeholders star...]]></description><link>https://devs.monade.io/speed-up-rendering-in-your-angular-application</link><guid isPermaLink="true">https://devs.monade.io/speed-up-rendering-in-your-angular-application</guid><category><![CDATA[Angular]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[performance]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Andrea Massioli]]></dc:creator><pubDate>Wed, 17 Aug 2022 14:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/lFMIQ6AiiW8/upload/v1658818635810/oPi8dD1ui.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After working with Angular for quite some time, I have come to love how you can build modular, scalable applications.</p>
<p>The road to using this framework effectively can be quite a bumpy one though, or at least I know it was for me! As stakeholders started to use my first app and requirements came in to add features, my code started to get increasingly messy, and <strong>the UI got pretty sluggish, pretty fast</strong>.</p>
<p>Luckily, the web abounds with resources and the Angular team worked overtime to give us the tools we need to make things better. In this article, I will present you with some concepts that are sure to help you build faster apps <em>AND</em> improve their architecture.</p>
<p>Please note that all the info I mention here assumes that we are working with Angular 14.</p>
<h3 id="heading-lazy-loading-feature-modules">Lazy loading Feature Modules</h3>
<p>Here is a beginner tip, yet one that is worth remarking: using your Angular modules properly can decrease the initial loading time of your app dramatically thanks to lazy loading. If you come from a different background, you might realize soon enough that you can mostly ignore NgModules when building your application and create a plain component tree; this would not be a smart choice, though.
As modules are one of the most defining and useful features of this framework, not taking the time to understand them would kill the purpose of using Angular for your project.</p>
<p>Let's say we are building an app that includes a couple of sections, one for managing users and one for browsing the history of orders. I know this is very simplistic, but please bear with me. The Angular way of doing this would consist of creating two <strong>Feature Modules</strong>, UsersModule and OrdersModule.
A Feature Module (or Domain Module, according to <a target="_blank" href="https://angular.io/guide/module-types">the official Angular docs</a>) is an NgModule that is organized around a feature, business domain, or user experience. By using these we can split concerns throughout our application, thus improving its architecture, and this is a very neat achievement per se.</p>
<p>Now, let's configure some routes in the AppRoutingModule and see how it is going to affect performance.
A very old way of doing this would be the following</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { RouterModule, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/router'</span>;
<span class="hljs-keyword">import</span> { OrdersModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./features/orders/orders.module'</span>;
<span class="hljs-keyword">import</span> { UsersModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./features/users/users.module'</span>;
<span class="hljs-keyword">import</span> { HomeComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./home/home.component'</span>;

<span class="hljs-keyword">const</span> routes: Routes = [
  { path: <span class="hljs-string">''</span>, component: HomeComponent },
  {
    path: <span class="hljs-string">'users'</span>,
    loadChildren: <span class="hljs-function">() =&gt;</span> UsersModule
  },
  {
    path: <span class="hljs-string">'orders'</span>,
    loadChildren: <span class="hljs-function">() =&gt;</span> OrdersModule
  }
];

<span class="hljs-meta">@NgModule</span>({
  imports: [RouterModule.forRoot(routes)],
  <span class="hljs-built_in">exports</span>: [RouterModule]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppRoutingModule { }
</code></pre>
<p>We will not settle for this solution even if it works, and here is why. As we import OrdersModule and UsersModule, Webpack is going to bundle them with AppModule, which means that when the user browses OrdersModule, it is not going to be loaded until UsersModule is also available and vice versa. Worse still, when the user browses the home page they are going to download two modules they don't need yet before they get access to the one they need, which is AppModule.</p>
<p>We can avoid this by using a different syntax:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { RouterModule, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/router'</span>;
<span class="hljs-keyword">import</span> { HomeComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./home/home.component'</span>;

<span class="hljs-keyword">const</span> routes: Routes = [
  { path: <span class="hljs-string">''</span>, component: HomeComponent },
  {
    path: <span class="hljs-string">'users'</span>,
    loadChildren: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./features/users/users.module'</span>).then(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.UsersModule)
  },
  {
    path: <span class="hljs-string">'orders'</span>,
    loadChildren: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./features/orders/orders.module'</span>).then(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.OrdersModule)
  }
];

<span class="hljs-meta">@NgModule</span>({
  imports: [RouterModule.forRoot(routes)],
  <span class="hljs-built_in">exports</span>: [RouterModule]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppRoutingModule { }
</code></pre>
<p>This way UsersModule and OrdersModule each get bundled in their own file and get <strong>lazily loaded</strong> when the user browses the proper route. Imagine the impact this could have on a real-world, large-scale application startup. On the other hand, as the user browses the application they will experiment some lag due to the relevant chunks getting downloaded. Well, we can do even better!</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@NgModule</span>({
  imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
  <span class="hljs-built_in">exports</span>: [RouterModule]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppRoutingModule { }
</code></pre>
<p>By adding <code>{ preloadingStrategy: PreloadAllModules }</code>, we change the loading behavior to this:</p>
<ol>
<li>The user browses a route</li>
<li>The browser downloads the relevant chunk along with the main one (the one which contains AppModule)</li>
<li>The UI is loaded and the user can start using the web app</li>
<li>In the background, the other chunks get downloaded</li>
<li>When the user browses a different route the relevant chunk is already loaded, making for a smooth navigation</li>
</ol>
<p>Nice! We now know everything we need to speed up the initial rendering while separating concerns in our application at a high level. I highly recommend spending some time looking up other commonly used NgModule patterns you can use to split concerns even further, such as the usage of Shared Modules.</p>
<p>This does not improve rendering performance inside our Feature Modules at all though, can we do something about that?</p>
<h3 id="heading-enter-changedetectionstrategyonpush">Enter ChangeDetectionStrategy.OnPush</h3>
<p>In most cases, the key as to why Angular apps slow down as they get bigger resides in how many times each component is rendered, that is in which cases the framework detects changes that are relevant to each component (thus re-rendering it).
In fact, by default, an Angular component gets re-rendered in a variety of cases most of which are not actually useful. A simple yet instructive way to observe this would be to pick a component, preferably one that is nested in a complex hierarchy, write an onRender method that just performs a console.log, and add <code>{{ onRender() }}</code> to the template to have an idea of how many times it is rendered. You will have a fair amount of <em>Why is it getting re-rendered again?</em> moments, even while interacting with different components!
We can change this by using the <strong>OnPush</strong> change detection strategy for our component:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Component</span>({
  selector: <span class="hljs-string">'app-users-list'</span>,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: <span class="hljs-string">`
    &lt;ng-container *ngIf="users"&gt;
      &lt;app-user-card *ngFor="let user of users" [user]="user"&gt;&lt;/app-user-card&gt;
    &lt;/ng-container&gt;
  `</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersListComponent <span class="hljs-keyword">implements</span> OnInit {
  users?: UserApi[];

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> usersService: UsersService</span>) { }

  ngOnInit(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.usersService.getUsers().subscribe(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> <span class="hljs-built_in">this</span>.users = users);
  }
}
</code></pre>
<p>This adjustment will dramatically decrease the number of renders in complex apps, but while experimenting with it you will notice that it does not display everything you expect; this would be the case if, as in the snippet above, it fetches data through a service and then it is supposed to show it. Why is that?
OnPush changes the behavior for the component to make it re-render <strong>only when one of its Inputs changes</strong>. Therefore, you should only use OnPush in components that behave like pure functions, that is if they only depend on their Inputs and not on any other external factor (e.g.: an XHR call, an attribute inside a service).</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Component</span>({
  selector: <span class="hljs-string">'app-users-list'</span>,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: <span class="hljs-string">`
    &lt;app-user-card *ngFor="let user of users" [user]="user"&gt;&lt;/app-user-card&gt;
  `</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersListComponent {
  <span class="hljs-meta">@Input</span>() users!: UserApi[];
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-meta">@Component</span>({
  selector: <span class="hljs-string">'app-users'</span>,
  template: <span class="hljs-string">`
    &lt;app-users-list *ngIf="(users$ | async) as users" [users]="users"&gt;&lt;/app-users-list&gt;
  `</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersComponent {
  users$ = <span class="hljs-built_in">this</span>.usersService.getUsers();

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> usersService: UsersService</span>) { }
}
</code></pre>
<h3 id="heading-container-and-presentational-components">Container and Presentational Components</h3>
<p>The two snippets above introduce us to a very useful pattern for component-based applications, that is Container and Presentational Components <a target="_blank" href="https://jackthenomad.com/how-to-write-good-composable-and-pure-components-in-angular-2-1756945c0f5b"><code>a.k.a. Smart and Dumb Components</code></a>. This pattern is especially useful when using a state manager, but it remains a godsend even when that's not the case.</p>
<p>Container components, such as UsersComponent, are allowed to contain side effects along with state and logic that belongs to the business domain. If you are using NgRx or another state manager of your choice, then the responsibility of a Container component is to make data of interest from the store available through selectors and to map Output events from Presentational components into action dispatches. We cannot use OnPush here!
We usually keep Container components in the containers/ subfolder of our feature modules.</p>
<p>Presentational components, such as UsersListComponent, have a state which only comprises their Inputs and, if needed, some UI state (e.g.: is this dropdown open?); they pass on user interactions to their parent components through Outputs. Injecting services is not recommended unless they have nothing to do with business logic. This is strictly when you should use ChangeDetectionStrategy.OnPush, as there is no downside at all. Sometimes you will still need to trigger change detection for very particular reasons; in those cases, you will want to trigger it explicitly with a ChangeDetectorRef instance.
We usually keep Presentational components in the components/ subfolder of our feature modules.
As they are stateless from a business logic perspective, Presentational components are easily reusable and much easier to unit test than your classic, obscure, spaghetti component.</p>
<h3 id="heading-methods-and-getters-in-the-template">Methods and Getters in the template</h3>
<p>If you have been using methods and getters in your bindings, you might want to reconsider that as it does slow down your app as opposed to other frameworks.
As Angular can only render a component template in its entirety, all bindings are evaluated at each render, which prompts all related methods and getters to be called even if they have not changed. This can be improved, of course.</p>
<p>The most obvious way to work around with issue is to replace these getters and methods with additional variables which only get reassigned when they actually change. This can happen in a variety of cases, such as at the end of an HTTP request, after another variable changes, or, most common for Presentational Components, as an Input changes via the onChanges lifecycle hook. This sounds pretty tedious, is there another way?</p>
<p>Sure, we can use <strong>pipes</strong>.</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Pipe</span>({
  name: <span class="hljs-string">'userDescription'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UserDescriptionPipe <span class="hljs-keyword">implements</span> PipeTransform {
  transform(user: UserApi): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${user.firstName}</span> <span class="hljs-subst">${user.lastName}</span>`</span>;
  }
}
</code></pre>
<p>This pretty much looks like using a method in the component class, but it's going to perform better because pipes are <em>pure</em> by default, which means that they are only going to be re-evaluated when their inputs change. Plus, it is reusable!</p>
<p>There is a caveat, though. Consider this example:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Pipe</span>({
  name: <span class="hljs-string">'userDescription'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UserDescriptionPipe <span class="hljs-keyword">implements</span> PipeTransform {
  transform(user: UserApi): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${user.firstName}</span> <span class="hljs-subst">${user.lastName}</span> - <span class="hljs-subst">${user.address.zipCode}</span>`</span>;
  }
}
</code></pre>
<p>The issue is that pure pipes do not get re-rendered if <em>a non-primitive attribute inside one of its parameters changes</em> (in this case, that would be <code>user.address</code>). To account for this, we can either:</p>
<ol>
<li>set <code>pure: false</code> in the Pipe decorator to make it react to impure changes. This would make it less efficient</li>
<li>treat the parameters as immutable objects, that is reassign the object instead of mutating it, e.g. with <code>this.user = { ...user, address: newAddress }</code> as opposed to <code>this.user.address = newAddress</code>. By doing this we can keep the pipe pure; besides, we probably want to do this anyway because of how Input change detection works.</li>
</ol>
<h3 id="heading-conclusions">Conclusions</h3>
<p>Some of the techniques are pretty quick to implement, while others bring you to review your app architecture. That, along with how each one affects a different aspect of Angular app slowdowns should hopefully make it helpful to most developers who need a performance boost for their app.
If you liked this article, especially the OnPush part, you might want to give NgRx a chance next. While it does not improve performance directly, it fits the architecture I described perfectly and it will make your app structure more predictable.</p>
<h3 id="heading-about-us">About Us</h3>
<p>This article is part of the <a target="_blank" href="https://monade.io">Mònade</a> Developers Blog, written by <a target="_blank" href="https://hashnode.com/@Andreammon">Andrea Massioli</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Flutter - 3 different state management options]]></title><description><![CDATA[Let's see some of the commonly used techniques to manage states in our applications
setState
This example shows the most common situation where a stateful widget has to share its state with some stateless sub widgets and this is accomplished by passi...]]></description><link>https://devs.monade.io/flutter-state-management-patterns-methods-bloc</link><guid isPermaLink="true">https://devs.monade.io/flutter-state-management-patterns-methods-bloc</guid><category><![CDATA[Flutter]]></category><category><![CDATA[State Management ]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[app development]]></category><category><![CDATA[BLoC]]></category><dc:creator><![CDATA[Mattia Cecchini]]></dc:creator><pubDate>Wed, 03 Aug 2022 13:09:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659531341652/2PKYHlEWc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's see some of the commonly used techniques to manage states in our applications</p>
<h3 id="heading-setstate">setState</h3>
<p>This example shows the most common situation where a stateful widget has to share its state with some stateless sub widgets and this is accomplished by passing props.
If we want to update the state from a sub-widget we have to share also a method to update it, and we can pass it in props too.
It's a common pattern that you can find in almost all declarative UI frontend frameworks.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">const</span> MyApp({Key? key}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  State&lt;MyApp&gt; createState() =&gt; _MyAppState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyAppState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyApp</span>&gt; </span>{
  <span class="hljs-comment">// state</span>
  <span class="hljs-built_in">int</span> count = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// method to update state</span>
  <span class="hljs-keyword">void</span> increment() {
    setState(() {
      count++;
    });
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: Center(
        child: Parent(
          count: count,
          increment: increment,
        ),
      ),
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> count;
  <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-built_in">Function</span>() increment;

  <span class="hljs-keyword">const</span> Parent({Key? key, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.count, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.increment})
      : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Child(
      count: count,
      increment: increment,
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Child</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> count;
  <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-built_in">Function</span>() increment;

  <span class="hljs-keyword">const</span> Child({Key? key, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.count, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.increment})
      : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> ElevatedButton(
      onPressed: increment,
      child: Text(<span class="hljs-string">"<span class="hljs-subst">$count</span>"</span>),
    );
  }
}
</code></pre>
<p>For an app state that you need to modify from many different places, you’d have to pass around a lot of callbacks, and this gets old and messy pretty quickly</p>
<p>We can also pass Widgets as props
With widget composition, we can solve part of this problem, with this trick the child component can access the state without getting it from the parent</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">const</span> MyApp({Key? key}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  State&lt;MyApp&gt; createState() =&gt; _MyAppState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyAppState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyApp</span>&gt; </span>{
  <span class="hljs-comment">// state</span>
  <span class="hljs-built_in">int</span> count = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// method to update state</span>
  <span class="hljs-keyword">void</span> increment() {
    setState(() {
      count++;
    });
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: Center(
        child: Parent(
          child: Child(
            count: count,
            increment: increment,
          ),
        ),
      ),
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Parent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> Widget child;

  <span class="hljs-keyword">const</span> Parent({Key? key, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.child}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> child;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Child</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> count;
  <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-built_in">Function</span>() increment;

  <span class="hljs-keyword">const</span> Child({Key? key, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.count, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.increment})
      : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> ElevatedButton(
      onPressed: increment,
      child: Text(<span class="hljs-string">"<span class="hljs-subst">$count</span>"</span>),
    );
  }
}
</code></pre>
<p>Drilling props could also have some performance issues, because every time you update a state, all the chain of widgets from the stateful widget will be rebuilt</p>
<p>And what if we need to share some global states, maybe persistent through route changes, this can be hard to handle only by drilling props</p>
<p>So setState is useful for widget-specific, ephemeral states. For global and persistent states we need something more</p>
<h3 id="heading-provider-package">Provider package</h3>
<p><a target="_blank" href="https://pub.dev/packages/provider">https://pub.dev/packages/provider</a></p>
<p>Flutter indeed has mechanisms for widgets to provide data and services to their descendants with some low-level widgets (InheritedWidget, InheritedNotifier, InheritedModel, and more)</p>
<p>But instead of using those low-level widgets, we can use this package called Provider.
We just need to understand these 3 concepts:</p>
<ul>
<li>ChangeNotifier</li>
<li>ChangeNotifierProvider</li>
<li>Consumer / Provider.of</li>
</ul>
<h4 id="heading-changenotifier">ChangeNotifier</h4>
<p>ChangeNotifier is a simple mixin included in the Flutter SDK which provides change notifications to its listeners</p>
<p>To notify the listeners you have to call the notifyListeners() method from ChangeNotifier every time you update the state</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> <span class="hljs-title">with</span> <span class="hljs-title">ChangeNotifier</span> </span>{
  <span class="hljs-comment">// state</span>
  <span class="hljs-built_in">int</span> count = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// increment counter</span>
  <span class="hljs-keyword">void</span> increment() {
    count++;
    notifyListeners();
  }
}
</code></pre>
<p>ChangeNotifier doesn't require widgets to work so you can test it standalone</p>
<pre><code class="lang-dart">test(<span class="hljs-string">'increment counter'</span>, () {
    <span class="hljs-keyword">final</span> model = Counter();
    <span class="hljs-keyword">final</span> count = model.count;
    model.addListener(() {
      expect(model.count, greaterThan(count));
    });
    model.increment();
  });
</code></pre>
<h4 id="heading-changenotifierprovider">ChangeNotifierProvider</h4>
<p>ChangeNotifierProvider is the widget that provides an instance of a ChangeNotifier to its descendants. It comes from the Provider package.</p>
<p>Usually, you don’t want to place ChangeNotifierProvider higher than necessary, but just above the widgets that need to access it</p>
<pre><code class="lang-dart">ChangeNotifierProvider(
  create: (context) =&gt; Counter(),
  child: <span class="hljs-keyword">const</span> MyApp(),
),
</code></pre>
<p>If you want to provide more than one ChangeNotifier, you can use MultiProvider</p>
<pre><code class="lang-dart">MultiProvider(
  providers: [
    ChangeNotifierProvider(
      create: (context) =&gt; Counter(),
    ),
    ...
  ],
  child: <span class="hljs-keyword">const</span> MyApp(),
),
</code></pre>
<h4 id="heading-consumer">Consumer</h4>
<p>To listen to state changes we can use the Consumer widget, specifying which model you want to access in the template</p>
<pre><code class="lang-dart">Consumer&lt;Counter&gt;(
  builder: (context, model, child) {
    <span class="hljs-keyword">return</span> Column(
      children: [
        ElevatedButton(
          onPressed: model.increment,
          child: Text(<span class="hljs-string">"<span class="hljs-subst">${model.count}</span>"</span>),
        ),
        <span class="hljs-comment">// ExpensiveWidget without rebuilding every time.</span>
        child,
      ],
    );
  },
  child: <span class="hljs-keyword">const</span> ExpensiveWidget(),
)
</code></pre>
<ul>
<li><em>builder</em> is the function that is called for rebuilding the returned widgets, whenever the ChangeNotifier notifies events (when you call notifyListeners() in your model)<ul>
<li><em>child</em> parameter, is there for optimization. If you have a large widget subtree under your Consumer that doesn’t change when the model changes, you can construct it once and get it through the builder.</li>
</ul>
</li>
</ul>
<p>It is best practice to put your Consumer widgets as deep in the tree as possible. You don’t want to rebuild large portions of the UI just because some detail somewhere changed.</p>
<h4 id="heading-providerof">Provider.of</h4>
<p>Another way to access the state and attach widgets as listeners to ChangeNotifier is by calling Provider.of(context) inside the build function of a widget</p>
<pre><code class="lang-dart">...
Widget build(BuildContext context) {
  <span class="hljs-comment">// access the state and register listener to ChangeNotifier similar to using Consumer as a wrapper of this widget</span>
  <span class="hljs-keyword">final</span> model = Provider.of&lt;Counter&gt;(context)
  ...
}
</code></pre>
<p>Sometimes you don't want to register a listener that rebuilds the current widget on every change, but you just want to access the current state, for example in callbacks</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> myFunction() {
  <span class="hljs-keyword">final</span> model = Provider.of&lt;Counter&gt;(context, listen: <span class="hljs-keyword">false</span>);
  ...
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659531146283/HDQRE4uOR.png" alt="provider.png" /></p>
<h4 id="heading-combine-providers">Combine providers</h4>
<p>ProxyProvider is a provider that combines multiple values from other providers into a new object and sends the result to Provider
This new object will then be updated whenever one of the providers we depend on gets updated.</p>
<pre><code class="lang-dart">MultiProvider(
  providers: [
    ChangeNotifierProvider(create: (_) =&gt; Counter()),
    ChangeNotifierProxyProvider&lt;Counter, SubCounter&gt;(
      create: (context) =&gt; SubCounter(<span class="hljs-number">0</span>),
      update: (context, counter, subcounter) =&gt; SubCounter(counter.count),
    ),
  ],
  child: Foo(),
);
</code></pre>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SubCounter</span> <span class="hljs-title">with</span> <span class="hljs-title">ChangeNotifier</span> </span>{
  SubCounter(<span class="hljs-keyword">this</span>.start);

  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> start;
  <span class="hljs-built_in">int</span> count = <span class="hljs-number">0</span>;

  <span class="hljs-built_in">int</span> <span class="hljs-keyword">get</span> total =&gt; start + count;

  <span class="hljs-keyword">void</span> increment() {
    count++;
    notifyListeners()
  }
}
</code></pre>
<h4 id="heading-final-considerations">Final considerations</h4>
<p>With Provider and ChangeNotifier you can accomplish all your needs in terms of state management, but having your models and their business logic in the same class is kind of messy in complex projects</p>
<h3 id="heading-bloc-pattern">BLoC pattern</h3>
<p>This design pattern helps to separate presentation from business logic. Following the BLoC pattern facilitates testability and reusability</p>
<p>Data will be flowing from the BLOC to the UI or even from UI to BLOC in form of streams</p>
<p>To visualize the notion of a stream you can consider a pipe with two ends, only one allowing to insert something into it. When you insert something into the pipe it flows inside and gets out from the other end
The concept is the same as rxjs Observables if you are familiar with</p>
<h4 id="heading-implementing-the-pattern">Implementing the pattern</h4>
<p><a target="_blank" href="https://pub.dev/packages/flutter_bloc">https://pub.dev/packages/flutter_bloc</a></p>
<p>This package uses Provider under the hood to share the streams of your changing states inside the application</p>
<p>Cubit and Bloc are the classes in this package to implement these streams</p>
<p>Both Blocs and Cubits will ignore duplicate states so it's a good practice to create comparable states, overriding ==operator and hashValue or using <a target="_blank" href="https://pub.dev/packages/equatable">equatable package</a></p>
<p>It's a good practice to emit immutable objects on streams</p>
<h4 id="heading-bloc">Bloc</h4>
<p>Implementing the Bloc class creates 2 streams, one to emit the state from the Bloc to the UI and one to emit events from the UI to the Bloc</p>
<p><img src="https://raw.githubusercontent.com/felangel/bloc/master/docs/assets/bloc_architecture_full.png" alt="bloc" /></p>
<p>In the constructor, we can define how the Bloc should react to the events emitted from the UI and we can set the initial state</p>
<p>With the on\ method, we can listen to events coming from the UI, and in the callback, we can emit a new state using the emitter that you will receive from the parameters or you can emit errors with addError method</p>
<p>Inside a Bloc, we can access the current state via the state getter</p>
<p>From the UI we can emit new events with add method exposed by the Bloc class</p>
<p>We can retrieve our Bloc from the UI using Provider</p>
<p>Events are handled by default concurrently, but we can trace them very well with the Bloc class and we can observe the Bloc and do stuff by overriding methods like:</p>
<ul>
<li>onEvent</li>
<li>onChange (you will receive the old state and the new one)</li>
<li>onTransition (similar to onChange but it contains also the event that triggered the state change)</li>
<li>onError methods</li>
</ul>
<p>You can also provide a custom EventTransformer to change the way incoming events are processed by the Bloc. Check out package <a target="_blank" href="https://pub.dev/packages/bloc_concurrency">bloc_concurrency</a> for an opinionated set of event transformers</p>
<p><img src="https://raw.githubusercontent.com/felangel/bloc/master/docs/assets/bloc_flow.png" alt="bloc_flow" /></p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span>&lt;<span class="hljs-title">CounterEvent</span>, <span class="hljs-title">CounterState</span>&gt; </span>{
  CounterBloc() : <span class="hljs-keyword">super</span>(CounterState(<span class="hljs-number">0</span>)){
    <span class="hljs-keyword">on</span>&lt;CounterIncrementEvent&gt;(_increment, transformer: sequential());
  }

  <span class="hljs-keyword">void</span> _increment(CounterEvent event, Emitter&lt;CounterState&gt; emit) <span class="hljs-keyword">async</span> {
    emit(CounterState(state.value + <span class="hljs-number">1</span>));
    <span class="hljs-comment">// addError(Exception('increment error!'), StackTrace.current);</span>
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onEvent(CounterEvent event) {
    <span class="hljs-keyword">super</span>.onEvent(event);
    <span class="hljs-built_in">print</span>(event);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onChange(Change&lt;<span class="hljs-built_in">int</span>&gt; change) {
    <span class="hljs-keyword">super</span>.onChange(change);
    <span class="hljs-built_in">print</span>(change);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onTransition(Transition&lt;CounterEvent, CounterState&gt; transition) {
    <span class="hljs-keyword">super</span>.onTransition(transition);
    <span class="hljs-built_in">print</span>(transition);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onError(<span class="hljs-built_in">Object</span> error, StackTrace stackTrace) {
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'<span class="hljs-subst">$error</span>, <span class="hljs-subst">$stackTrace</span>'</span>);
    <span class="hljs-keyword">super</span>.onError(error, stackTrace);
  }
}

<span class="hljs-meta">@immutable</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterEvent</span> </span>{}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterIncrementEvent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CounterEvent</span> </span>{}

<span class="hljs-meta">@immutable</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterState</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> value;

  <span class="hljs-keyword">const</span> CounterState(<span class="hljs-keyword">this</span>.value);

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">int</span> <span class="hljs-keyword">get</span> hashCode =&gt; value.hashCode;

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">bool</span> <span class="hljs-keyword">operator</span> ==(<span class="hljs-built_in">Object</span> other) {
    <span class="hljs-keyword">if</span> (other <span class="hljs-keyword">is</span> CounterState) {
      <span class="hljs-keyword">return</span> other.value == value;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
  }
}
</code></pre>
<p>bloc_test is a usefull package for testing Blocs <a target="_blank" href="https://pub.dev/packages/bloc_test">https://pub.dev/packages/bloc_test</a></p>
<pre><code class="lang-dart">blocTest&lt;CounterBloc, CounterState&gt;(
  <span class="hljs-string">'increment counter'</span>,
  build: () =&gt; CounterBloc(),
  act: (bloc) =&gt; bloc
    ..add(CounterIncrementEvent())
    ..add(CounterIncrementEvent()),
  expect: () =&gt; &lt;CounterState&gt;[
    CounterState(<span class="hljs-number">1</span>),
    CounterState(<span class="hljs-number">2</span>),
  ],
);
</code></pre>
<h4 id="heading-cubit">Cubit</h4>
<p>This is a subset of the Bloc class, it reduces complexity and simplifies boilerplate for managing simpler states
It eliminates the event stream and uses functions instead, to update the state</p>
<p><img src="https://raw.githubusercontent.com/felangel/bloc/master/docs/assets/cubit_architecture_full.png" alt="cubit" /></p>
<p>We can define a new Cubit specifying the object type to be transmitted into the stream (in this case CounterState) and emitting new values with emit method or emitting errors with addError</p>
<p>In the constructor, it requires an initial state</p>
<p>Inside a Cubit, we can access the current state via the state getter</p>
<p>We can observe the Cubit and do stuff like in Bloc but we can override only the onChange and onError methods</p>
<p>Compared with Bloc we lose some traceability to reduce complexity</p>
<p><img src="https://raw.githubusercontent.com/felangel/bloc/master/docs/assets/cubit_flow.png" alt="cubit_flow" /></p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterCubit</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Cubit</span>&lt;<span class="hljs-title">CounterState</span>&gt; </span>{
  CounterCubit() : <span class="hljs-keyword">super</span>(<span class="hljs-keyword">const</span> CounterState(<span class="hljs-number">0</span>));

  <span class="hljs-keyword">void</span> increment() {
    emit(CounterState(state.value + <span class="hljs-number">1</span>));
    <span class="hljs-comment">// addError(Exception('increment error!'), StackTrace.current);</span>
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onChange(Change&lt;CounterState&gt; change) {
    <span class="hljs-keyword">super</span>.onChange(change);
    <span class="hljs-built_in">print</span>(change);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onError(<span class="hljs-built_in">Object</span> error, StackTrace stackTrace) {
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'<span class="hljs-subst">$error</span>, <span class="hljs-subst">$stackTrace</span>'</span>);
    <span class="hljs-keyword">super</span>.onError(error, stackTrace);
  }
}

<span class="hljs-meta">@immutable</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterState</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> value;

  <span class="hljs-keyword">const</span> CounterState(<span class="hljs-keyword">this</span>.value);

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">int</span> <span class="hljs-keyword">get</span> hashCode =&gt; value.hashCode;

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">bool</span> <span class="hljs-keyword">operator</span> ==(<span class="hljs-built_in">Object</span> other) {
    <span class="hljs-keyword">if</span> (other <span class="hljs-keyword">is</span> CounterState) {
      <span class="hljs-keyword">return</span> other.value == value;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
  }
}
</code></pre>
<p>You can test it in the same way as Bloc with the bloc_test package</p>
<pre><code class="lang-dart">blocTest&lt;CounterCubit, CounterState&gt;(
  <span class="hljs-string">'increment counter'</span>,
  build: () =&gt; CounterCubit(),
  act: (bloc) =&gt; bloc
    ..increment()
    ..increment(),
  expect: () =&gt; &lt;CounterState&gt;[
    CounterState(<span class="hljs-number">1</span>),
    CounterState(<span class="hljs-number">2</span>),
  ],
);
</code></pre>
<p>If you don't know if you should implement your state as Cubit or Bloc, just start with Cubit and the eventually refactor to Bloc on needs</p>
<h4 id="heading-combine-blocs">Combine Blocs</h4>
<p>You should not do this, sibling dependencies between two entities in the same architectural layer should be avoided because are hard to maintain, no Bloc should know about any other Bloc</p>
<p>But if you have to combine Blocs and get notified of state changes, we can subscribe to other Bloc dependencies in the Bloc constructor
These dependencies have to be provided in the constructor's arguments</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FilteredCounterBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span>&lt;<span class="hljs-title">FilteredCounterEvent</span>, <span class="hljs-title">FilteredCounterState</span>&gt; </span>{
  <span class="hljs-keyword">final</span> counterBloc CounterBloc;
  StreamSubscription counterSubscription;

  FilteredCounterBloc({<span class="hljs-meta">@required</span> <span class="hljs-keyword">this</span>.counterBloc}) {
    counterSubscription = counterBloc.listen((state) {
      <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> CounterState) {
        add(<span class="hljs-keyword">this</span>.counterUpdated);
      }
    });
  }

  <span class="hljs-keyword">void</span> counterUpdate(CounterState state) {
    <span class="hljs-comment">// do something</span>
  }
  <span class="hljs-comment">// ...</span>
</code></pre>
<h4 id="heading-widgets">Widgets</h4>
<h5 id="heading-blocprovider">BlocProvider</h5>
<p>Same as with Provider we have to provide our Blocs to be accessible in our application
You don’t want to place BlocProvider higher than necessary, but just above the widgets that need to access it</p>
<pre><code class="lang-dart">BlocProvider(
  create: (context) =&gt; CounterCubit(), <span class="hljs-comment">// or CounterBloc()</span>
  child: MyApp(),
)
</code></pre>
<p>If you want to provide more than one Bloc, you can use MultiBlocProvider</p>
<pre><code class="lang-dart">MultiBlocProvider(
  providers: [
    BlocProvider(
      create: (context) =&gt; CounterCubit(),
    ),
    BlocProvider(
      create: (context) =&gt; CounterBloc(),
    ),
    ...
  ],
  child: <span class="hljs-keyword">const</span> MyApp(),
),
</code></pre>
<p>RepositoryProvider is a Flutter widget that provides a repository to its children via RepositoryProvider.of(context).
It is used as dependency injection (DI) widget so that a single instance of a repository can be provided to multiple widgets within a subtree.
BlocProvider should be used to provide Blocs whereas RepositoryProvider should only be used for repositories.
If you want to provide more than one Repository, you can use MultiRepositoryProvider</p>
<h5 id="heading-blocbuilder-bloclistener-and-other-widgets-to-react-to-state-changes">BlocBuilder, BlocListener, and other widgets to react to state changes</h5>
<p>To listen to state changes we can use the BlocBuilder widget specifying which Bloc you want to access and the emitted data type in the template</p>
<pre><code class="lang-dart">BlocBuilder&lt;CounterCubit, CounterState&gt;(
  builder: (context, state) {
    <span class="hljs-keyword">return</span> ElevatedButton(
      onPressed: context.read&lt;CounterCubit&gt;().increment,
      child: Text(<span class="hljs-string">"<span class="hljs-subst">${state.value}</span>"</span>),
    );
  },
)

BlocBuilder&lt;CounterBloc, CounterState&gt;(
  builder: (context, state) {
    <span class="hljs-keyword">return</span> ElevatedButton(
      onPressed: () =&gt; context.read&lt;CounterBloc&gt;().add(CounterIncrementEvent()),
      child: Text(<span class="hljs-string">"<span class="hljs-subst">${state.value}</span>"</span>),
    );
  },
)
</code></pre>
<p>Use BlocListener (or MultiBlocListener) if the UI child isn't directly affected by state changing and you just need to do something in response to state changes like navigation or showing modals etc...</p>
<pre><code class="lang-dart"> BlocListener&lt;CounterCubit, CounterState&gt;(
  listener: (context, state) {
    <span class="hljs-keyword">if</span>(state.value == <span class="hljs-number">10</span>) {
      Navigator.of(context).pushNamed(<span class="hljs-string">"/someroute"</span>);
    }
  },
  child: ChildWidget(),
)
</code></pre>
<p>You can use BlocConsumer if you need both builder and listener</p>
<pre><code class="lang-dart">BlocConsumer&lt;CounterCubit, CounterState&gt;(
  listener: (context, state) {
    <span class="hljs-keyword">if</span>(state.value == <span class="hljs-number">10</span>) {
      Navigator.of(context).pushNamed(<span class="hljs-string">"/someroute"</span>);
    }
  },
  builder: (context, state) {
    <span class="hljs-keyword">return</span> Text(<span class="hljs-string">"<span class="hljs-subst">${state.value}</span>"</span>);
  },
)
</code></pre>
<p>You can use BlocSelector if you need to react only to a part of state changing</p>
<pre><code class="lang-dart">BlocSelector&lt;CounterCubit, CounterState, <span class="hljs-built_in">bool</span>&gt;(
  selector: (state) {
    <span class="hljs-keyword">return</span> state.value &gt; <span class="hljs-number">0</span>;
  },
  builder: (context, state) {
    <span class="hljs-keyword">return</span> Text(<span class="hljs-string">"is greater than zero? <span class="hljs-subst">${state}</span>"</span>);
  },
)
</code></pre>
<h5 id="heading-blocproviderof-and-context-shortcuts">BlocProvider.of and context shortcuts</h5>
<p>As anticipated, we can access our Blocs and Cubits from the UI using Provider</p>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> cubit = BlocProvider.of&lt;CounterCubit&gt;(context);
</code></pre>
<p>Or more simply using context</p>
<pre><code class="lang-dart"><span class="hljs-comment">// do not use it in the build method to access the state, use it to access the Bloc in callbacks</span>
<span class="hljs-keyword">final</span> cubit = context.read&lt;CounterCubit&gt;();
</code></pre>
<p>If we want the widget to be notified of state change</p>
<pre><code class="lang-dart"><span class="hljs-comment">// use it in the build method to rebuild the widget on state changes, not in callbacks only to access the state</span>
<span class="hljs-keyword">final</span> cubit = context.watch&lt;CounterCubit&gt;();
</code></pre>
<p>In addition, context.select can be used to retrieve part of a state and react to changes only when the selected part changes.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// use it in build method to rebuild the widget on selected state changes, not in callbacks only to access the state</span>
<span class="hljs-keyword">final</span> isCounterGreaterThenZero = context.select((CounterBloc b) =&gt; b.state.value &gt; <span class="hljs-number">0</span>);
</code></pre>
<h5 id="heading-observe-all-blocs">Observe all blocs</h5>
<p>BlocObserver can be used to observe all Blocs</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyBlocObserver</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BlocObserver</span> </span>{
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onCreate(BlocBase bloc) {
    <span class="hljs-keyword">super</span>.onCreate(bloc);
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'onCreate -- <span class="hljs-subst">${bloc.runtimeType}</span>'</span>);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onEvent(Bloc bloc, <span class="hljs-built_in">Object?</span> event) {
    <span class="hljs-keyword">super</span>.onEvent(bloc, event);
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'onEvent -- <span class="hljs-subst">${bloc.runtimeType}</span>, <span class="hljs-subst">$event</span>'</span>);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onChange(BlocBase bloc, Change change) {
    <span class="hljs-keyword">super</span>.onChange(bloc, change);
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'onChange -- <span class="hljs-subst">${bloc.runtimeType}</span>, <span class="hljs-subst">$change</span>'</span>);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onTransition(Bloc bloc, Transition transition) {
    <span class="hljs-keyword">super</span>.onTransition(bloc, transition);
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'onTransition -- <span class="hljs-subst">${bloc.runtimeType}</span>, <span class="hljs-subst">$transition</span>'</span>);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onError(BlocBase bloc, <span class="hljs-built_in">Object</span> error, StackTrace stackTrace) {
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'onError -- <span class="hljs-subst">${bloc.runtimeType}</span>, <span class="hljs-subst">$error</span>'</span>);
    <span class="hljs-keyword">super</span>.onError(bloc, error, stackTrace);
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> onClose(BlocBase bloc) {
    <span class="hljs-keyword">super</span>.onClose(bloc);
    <span class="hljs-built_in">print</span>(<span class="hljs-string">'onClose -- <span class="hljs-subst">${bloc.runtimeType}</span>'</span>);
  }
}

<span class="hljs-keyword">void</span> main() {
  BlocOverrides.runZoned(
    () {
      <span class="hljs-comment">// Bloc instances will use MyBlocObserver instead of the default BlocObserver.</span>
    },
    blocObserver: MyBlocObserver(),
  );
}
</code></pre>
<h2 id="heading-insights">Insights</h2>
<p><a target="_blank" href="https://docs.flutter.dev/development/data-and-backend/state-mgmt/options">Flutter dev - state management options</a></p>
<p><a target="_blank" href="https://bloclibrary.dev/">Bloc library documentation</a></p>
<p><a target="_blank" href="https://github.com/felangel/bloc/tree/master/examples">Bloc implementation examples</a></p>
<h2 id="heading-about-us">About Us</h2>
<p>This article is part of the <a target="_blank" href="https://monade.io">Mònade</a> Developers Blog, written by <a target="_blank" href="https://hashnode.com/@mattiacecchini">Mattia Cecchini</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to optimize DB writes in Ruby on Rails]]></title><description><![CDATA[Foreword
While read queries can heavily impact performance, writes too can do some damage. In this article, part 2 on our Rails Performance Series, we will examine ways to speed up write queries.
Checkout the part 1 about DB reads here.
Transactions
...]]></description><link>https://devs.monade.io/how-to-optimize-db-writes-in-ruby-on-rails</link><guid isPermaLink="true">https://devs.monade.io/how-to-optimize-db-writes-in-ruby-on-rails</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[Rails]]></category><dc:creator><![CDATA[Piero Dotti]]></dc:creator><pubDate>Wed, 06 Jul 2022 13:43:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657112997603/QUfQExPCf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-foreword">Foreword</h4>
<p>While read queries can heavily impact performance, writes too can do some damage. In this article, part 2 on our Rails Performance Series, we will examine ways to speed up write queries.</p>
<p><em><a target="_blank" href="https://devs.monade.io/how-to-optimize-rails-db-reads-in-rails">Checkout the part 1 about DB reads here.</a></em></p>
<h3 id="heading-transactions">Transactions</h3>
<p>Transactions allow us to execute a series of operations atomically, as they were a single operation. If any operation inside the transaction fails, the whole blocks is canceled, and no operation is persisted (rollback).</p>
<p>A nice thing to know is that a database is much faster at committing a transaction with <em>n</em> writes than <em>n</em> writes each.
So generally:</p>
<pre><code class="lang-ruby"><span class="hljs-number">1000</span>.times <span class="hljs-keyword">do</span>
  User.create!(<span class="hljs-symbol">email:</span> <span class="hljs-string">'hey@example.com'</span>)
<span class="hljs-keyword">end</span>
</code></pre>
<p>is much slower than</p>
<pre><code class="lang-ruby">User.transaction <span class="hljs-keyword">do</span>
  <span class="hljs-number">1000</span>.times <span class="hljs-keyword">do</span>
    User.create!(<span class="hljs-symbol">email:</span> <span class="hljs-string">'hey@example.com'</span>)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h3 id="heading-validations">Validations</h3>
<p>Rails validations are very useful, although they introduce an overhead on record save. Uniqueness constraints are particularly costly, as they imply a <code>SELECT</code> query before saving to check if the value respects the constraint.<br />
In some cases disabling validations can significantly speed up operations, especially when we are dealing with massive operations like imports and such.<br />
To skip validations we can call the save method as:</p>
<pre><code class="lang-ruby">record.save(<span class="hljs-symbol">validate:</span> <span class="hljs-literal">false</span>)
</code></pre>
<p>DO NOT do this unless you are sure that performance is a real problem.</p>
<h3 id="heading-massive-insertions-updates">Massive insertions / updates</h3>
<p>From Rails 6 onwards some handy methods were added to do mass operations, using a single <code>INSERT INTO</code> or <code>UPDATE</code> operation.</p>
<p>Those methods are <code>insert_all</code>, <code>insert_all!</code>, <code>upsert_all</code> and <code>upsert_all!</code>.</p>
<p>The main advantage is that insertion time is orders of magnitude faster.</p>
<p><strong>Warning:</strong> with those methods model validations and callbacks <strong>will not</strong> be invoked. (<code>before_create</code>, <code>after_save</code>, etc.)</p>
<p>If you're using Rails &lt; 6, you can achieve the same functionality using this gem:<br />
https://github.com/jamis/bulk_insert</p>
<h3 id="heading-massive-deletions">Massive deletions</h3>
<p>The same thing is valid for deletions.</p>
<p>If you need to prune mass data, consider that this:</p>
<pre><code class="lang-ruby">User.each(&amp;<span class="hljs-symbol">:destroy</span>)
</code></pre>
<p>Is much slower than this:</p>
<pre><code class="lang-ruby">User.transaction <span class="hljs-keyword">do</span>
  User.each(&amp;<span class="hljs-symbol">:destroy</span>)
<span class="hljs-keyword">end</span>
</code></pre>
<p>And it's <strong>much much</strong> slower than this:</p>
<pre><code class="lang-ruby">User.delete_all
</code></pre>
<p>But, as noted before, <code>delete_all</code> skips all validations and <code>before_destroy</code> hooks, so be aware of it.</p>
<h3 id="heading-minimize-number-of-queries">Minimize number of queries</h3>
<p>It's pretty obvious, but a way to reduce writing performance is, as always, to reduce the number of queries.</p>
<p>So, try to make changes to a model all in the same place or collect changes in the model and invoke a query just once.</p>
<p>For instance:</p>
<ul>
<li>Don't make call an <code>#update</code> in the <code>after_create</code> hook. Use <code>before_create</code> and change the column, instead.</li>
</ul>
<p><strong>Don't</strong></p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span></span>
  after_create <span class="hljs-keyword">do</span>
    update(<span class="hljs-symbol">is_valid_user:</span> <span class="hljs-literal">true</span>) <span class="hljs-keyword">if</span> email.ends_with?(<span class="hljs-string">'@gmail.com'</span>)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p><strong>Do</strong></p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span></span>
  before_create <span class="hljs-keyword">do</span>
    <span class="hljs-keyword">self</span>.is_valid_user = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> email.ends_with?(<span class="hljs-string">'@gmail.com'</span>)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<ul>
<li>Don't call #touch if you just made a <code>save</code> to the model. It's been already <code>touch</code>-ed by the save</li>
<li>Don't call save multiple times on the same model during the same request.</li>
</ul>
<p><strong>Don't</strong></p>
<pre><code class="lang-ruby">user.update!(<span class="hljs-symbol">email:</span> <span class="hljs-string">'___'</span>, <span class="hljs-symbol">password:</span> <span class="hljs-string">'___'</span>)
...
...
user.update!(<span class="hljs-symbol">is_valid:</span> <span class="hljs-literal">true</span>) <span class="hljs-keyword">if</span> user.email.ends_with?(<span class="hljs-string">'@gmail.com'</span>)
user.update!(<span class="hljs-symbol">metadata:</span> metadata) <span class="hljs-keyword">unless</span> metadata.<span class="hljs-literal">nil</span>?
</code></pre>
<p><strong>Do</strong></p>
<pre><code class="lang-ruby">user.email = <span class="hljs-string">'___'</span>
user.<span class="hljs-symbol">password:</span> <span class="hljs-string">'___'</span>
...
user.is_valid = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> user.email.ends_with?(<span class="hljs-string">'@gmail.com'</span>)
user.metadata = metadata <span class="hljs-keyword">unless</span> metadata.<span class="hljs-literal">nil</span>?
user.save! <span class="hljs-comment"># Just one query</span>
<span class="hljs-comment">######</span>
<span class="hljs-comment"># Or, as an alternative:</span>
<span class="hljs-comment">######</span>
user.assign_attributes(<span class="hljs-symbol">email:</span> <span class="hljs-string">'___'</span>, <span class="hljs-symbol">password:</span> <span class="hljs-string">'___'</span>)
...
user.is_valid = <span class="hljs-literal">true</span> <span class="hljs-keyword">if</span> user.email.ends_with?(<span class="hljs-string">'@gmail.com'</span>)
user.metadata = metadata <span class="hljs-keyword">unless</span> metadata.<span class="hljs-literal">nil</span>?
user.save! <span class="hljs-comment"># Just one query</span>
</code></pre>
<h3 id="heading-indexes-triggers-and-performance">Indexes, triggers and performance</h3>
<p>Indexes are great for performance, in general. They speed up read queries a LOT, making a trade-off between speed and occupied memory.</p>
<p>However, you should consider that they also add an extra overhead during writes. In general, this is trivial.</p>
<p>In some scenario, however, if you have too many (unused) indexes, you may see some slowdowns during inserts.</p>
<p>To find it out, just run the query in the console and check the execution time:</p>
<pre><code><span class="hljs-keyword">User</span> <span class="hljs-keyword">Create</span> (<span class="hljs-number">4.3</span>ms)  <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> "users" ("email", "created_at", "updated_at", "confirmation_token", "confirmation_sent_at") <span class="hljs-keyword">VALUES</span> (<span class="hljs-meta">$1</span>, <span class="hljs-meta">$2</span>, <span class="hljs-meta">$3</span>, <span class="hljs-meta">$4</span>, <span class="hljs-meta">$5</span>) <span class="hljs-keyword">RETURNING</span> "id"
</code></pre><p>In general, it should be a few milliseconds. If it's much higher (like 300ms), it could be caused by too many indexes.
Try to prune redundant ones.</p>
<p>A few hints:</p>
<ul>
<li>Indexes on column with a low cardinality are usually less effective and useless (example: booleans, enumerators, values often NULL)</li>
<li>Compound indexes always cover single indexes on the first column. So <code>INDEX ON (first_name, last_name)</code> also covers searches on the <code>first_name</code> column on ly (but not on <code>last_name</code>).</li>
</ul>
<p>The same issue can appear with triggers: don't over use them, because they can slow down a LOT your write performance.</p>
<h2 id="heading-about-us">About Us</h2>
<p>This article is part of the <a target="_blank" href="https://monade.io">Mònade</a> Developers Blog, written by <a class="user-mention" href="https://hashnode.com/@ProGM">Piero Dotti</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to optimize DB read operations in Ruby on Rails]]></title><description><![CDATA[Premise
Ruby on Rails is rarely seen as a framework oriented towards speed and performance. And that's true: Rails was born as a tool to speed up development and to make developers' life easier.
This must be contextualized, though. 
Those who say thi...]]></description><link>https://devs.monade.io/how-to-optimize-rails-db-reads-in-rails</link><guid isPermaLink="true">https://devs.monade.io/how-to-optimize-rails-db-reads-in-rails</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[Rails]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Piero Dotti]]></dc:creator><pubDate>Wed, 22 Jun 2022 09:29:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/lRoX0shwjUQ/upload/v1655890224296/KoBN3NHlP.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-premise">Premise</h2>
<p>Ruby on Rails is rarely seen as a framework oriented towards speed and performance. And that's true: Rails was born as a tool to speed up development and to make developers' life easier.</p>
<p>This must be contextualized, though. </p>
<p>Those who say this usually are talking about <strong>scaling</strong> problems. That is to say that when requests and concurrency grows Rails is easily outperformed by other more performant frameworks or languages: Rust, Elixir, and Java are good examples.</p>
<p>The point is that when we talk about this kind of problems we are talking about very heavy loads, thousands or tens of thousands requests per minutes.</p>
<p>On smaller loads Rails has no particular problems, and generally performance is more a developer <em>water cooler argument of discussion</em>.</p>
<p>We agree on the fact that a response time of 5ms vs 50ms is nicer to see, but to the final user this is rarely detectable, as we can expect 100-300ms of global network overhead.</p>
<p>So <strong>if you have performance problems on an application with a modest load the problems is your code, not Rails</strong>.</p>
<p>Don't get discouraged, this means two things:</p>
<ul>
<li>there is a lot of measures to take to increase performance;</li>
<li>you DO NOT have to rewrite your app in Rust🚀.</li>
</ul>
<h3 id="heading-note">Note</h3>
<p>Rails in dev mode is significantly slower than production mode. Test in production mode before concluding that your app is slow.</p>
<h3 id="heading-query-performance">Query performance</h3>
<p>The largest part of Rails performance problems are not actual Rails problems, but rather problems in the way we use ActiveRecord and the number of queries ran for each request.</p>
<p>To check wether this is our case it's enough to run the slow network request and check the server logs for something like this:</p>
<pre><code class="lang-bash">Completed 200 OK <span class="hljs-keyword">in</span> 72ms (Views: 43.6ms | ActiveRecord: 24.6ms | Allocations: 27391)
</code></pre>
<p>This is the recap of the request time, divided by each component. As you can see this request is fairly fast and ActiveRecord has a moderate impact on the overall request time.</p>
<p>On the contrary this log:</p>
<pre><code>Completed <span class="hljs-number">200</span> OK <span class="hljs-keyword">in</span> <span class="hljs-number">2800</span>ms (Views: <span class="hljs-number">80.6</span>ms | ActiveRecord: <span class="hljs-number">2719.2</span>ms | Allocations: xxxx)
</code></pre><p>means that there is a problem: <strong>the queries take to long!</strong>.</p>
<p>First we have to identify the kind of queries that are slow. Read queries (<code>SELECT</code>) or write queries (<code>INSERT</code>, <code>UPDATE</code>, <code>DELETE</code>).</p>
<h2 id="heading-read-queries">Read queries</h2>
<p>As a rule of thumb: the fewer queries, the better. This is because:</p>
<ul>
<li>Running a query has a fixed network and database processing overhead, not depending on the query complexity. Running 10 light queries costs more than running one big query.</li>
<li>Parsing a query is not free in Rails, as we have to instantiate models based on the query result</li>
<li>Databases are generally faster than Rails: it's better to make the database do the heavy search&amp;filtering work.</li>
</ul>
<h4 id="heading-the-n1-queries-problem">The n+1 queries problem</h4>
<p>Rails allows to handle models and relations in a very simple way, but this can lead to unoptimized queries. A typical problem is the "n+1 queries problem".  </p>
<p>This is the use case: we want to iterate on a models collection and, for each record, access one of its relationships to extract some attribute from this relationship.</p>
<p>Normally every time we access a relationship on a model Rails runs a SELECT to load the relationship data. This is also valid for the fetched relationships: trying to access a relationship of the previous one triggers another select, and so on.</p>
<p>Naturally, the more the record, the more the queries. An example:</p>
<pre><code class="lang-ruby">  users = User.all
  commenters = users.flat_map <span class="hljs-keyword">do</span> <span class="hljs-params">|user|</span>
    <span class="hljs-comment"># calling user.posts, triggers SELECT * FROM posts WHERE user_id = ?</span>
    user.posts.flat_map <span class="hljs-keyword">do</span> <span class="hljs-params">|post|</span> 
      <span class="hljs-comment"># post.comments triggers "SELECT * FROM comments WHERE post_id = ?"</span>
      <span class="hljs-comment"># .author also triggers "SELECT * FROM users WHERE user_id = ? LIMIT 1"</span>
      post.comments.map(&amp;<span class="hljs-symbol">:author</span>)
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
</code></pre>
<p>In this examples, 100 users with 100 posts each, each post with 10 comments, means ... <code>100+100 * 10 * 2 = 2100</code> queries. <strong>ARGH</strong></p>
<p>How can we solve this?</p>
<p>The idea is to <strong>preload</strong> with one (or few) queries the data before the <code>for</code> loop, to avoid running all the queries and to have all the data ready from the beginning.</p>
<p>Rails offers three main ways to preload, each composable with the existing query:</p>
<ul>
<li>The <code>eager_load</code> method alters the main query, adding a <code>LEFT OUTER JOIN</code> for each relationship to preload. It's the most efficient way counting the number of queries because only one very large query is executed, but can <strong>create conflicts with the other SQL constructs used</strong>. For example it can mangle with <code>select</code>, <code>distinct</code> and <code>group</code> methods and generate invalid sql.</li>
<li>The <code>preload</code> method loads the requested relationships in a separate query, with a single query for each relationship. It's a little less efficient than eager loading, but it's safer.</li>
<li>The <code>includes</code> method chooses based on context wether to use a <code>LEFT OUTER JOIN</code> or a separate query, checking for conflicts.</li>
</ul>
<p>The previous example optimized looks like this:</p>
<pre><code class="lang-ruby"> users = User.preload(<span class="hljs-symbol">posts:</span> { <span class="hljs-symbol">comments:</span> <span class="hljs-symbol">:author</span> })
 commenters = users.flat_map <span class="hljs-keyword">do</span> <span class="hljs-params">|user|</span>
    <span class="hljs-comment"># no query here</span>
    user.posts.flat_map <span class="hljs-keyword">do</span> <span class="hljs-params">|post|</span> 
      <span class="hljs-comment"># neither here</span>
      post.comments.map(&amp;<span class="hljs-symbol">:author</span>)
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
</code></pre>
<p>Using <code>preload</code> we will run a query for the users, a query for the posts, one for authors and one for comments. A total of <strong>4 queries</strong>, which even if large and time-consuming (for example 50ms each, which is <strong>a lot</strong>) will still be reasonably fast (200ms in total).</p>
<p>We are talking 50x just with a little optimization.</p>
<p><strong>Warning:</strong> often the n+1 problem is hidden, because Rails iterates implicitly on the data. As an example, every time we serialize a model that has a relation, that will trigger the problem.</p>
<p><strong>Pro tip:</strong> there is a little lovely gem which can, in some specific cases, solve the problem automagically: <a target="_blank" href="https://github.com/salsify/goldiloader">goldiloader</a>. It's always a good idea to install it.</p>
<h4 id="heading-manual-preloading">Manual preloading</h4>
<p>Sometimes the Rails automatic preload does not work, but it can serve as an inspiration on how to optimize our query!</p>
<p>Manual preloading is most useful when we are looping over data stored in the database.</p>
<p>The idea is: instead of using <code>find_by!</code> or <code>where</code> methods inside a loop, we preload the data before the loop and keep a key-value map to access rapidly preloaded data.</p>
<p>For example: we want to update all the <code>Post</code>s inside our app. Posts had a text field containing the author name, but we made the author a relationship on the post, and want to migrate from a text field to a reference field.</p>
<p>We would usually do:</p>
<pre><code class="lang-ruby">  Post.find_each <span class="hljs-keyword">do</span> <span class="hljs-params">|p|</span>
    p.user = User.find_by!(<span class="hljs-symbol">name:</span> p.author_name) <span class="hljs-comment"># a query for each post!</span>
    p.save!
  <span class="hljs-keyword">end</span>
</code></pre>
<p>Bad news: we have 100.000 posts, and Rails is still running after an hour. This is obviously slow. </p>
<p>Solution:</p>
<pre><code class="lang-ruby">  <span class="hljs-comment"># preloading all users in a name -&gt; user map</span>
  user_map = User.where(<span class="hljs-symbol">name:</span> Post.select(<span class="hljs-string">'DISTINCT author_name'</span>)).index_by(&amp;<span class="hljs-symbol">:name</span>)
  Post.find_each <span class="hljs-keyword">do</span> <span class="hljs-params">|p|</span>
    <span class="hljs-comment"># users are already there, this is very fast</span>
    p.user = user_map[p.author_name] <span class="hljs-params">||</span> (raise ActiveRecord::RecordNotFound)
    p.save!
  <span class="hljs-keyword">end</span>
</code></pre>
<p>This saves us all <code>find_by!</code> calls, 50% of the total queries is now gone!</p>
<h4 id="heading-unwanted-queries">Unwanted Queries</h4>
<p>Some rails’ models methods trigger queries, often unwanted, unexpected or unnecessary. It’s important to know when and where this could happen!</p>
<h5 id="heading-count">count</h5>
<p>Calling <code>#count</code> on a <code>has_many</code> relationship <strong>always</strong> triggers a query. Even if data has been loaded previously.
For example:</p>
<pre><code class="lang-ruby">user = User.first
user.posts.each { <span class="hljs-params">|p|</span> ... } <span class="hljs-comment"># this fires "SELECT * FROM posts WHERE user_id = ?"</span>
user.posts.size <span class="hljs-comment"># posts are cached, no query</span>
user.posts.count <span class="hljs-comment"># this triggers SELECT COUNT(*) FROM posts WHERE user_id = ?</span>
</code></pre>
<p>tldr; never use <code>#count</code>, use <code>#size</code>.</p>
<h5 id="heading-any-exists-and-present"><code>any?</code>, <code>exists?</code> and <code>present?</code></h5>
<p>These methods could potentially trigger an unwanted query if the relationship has not been already loaded. 
For example:</p>
<pre><code class="lang-ruby">user = User.first
<span class="hljs-keyword">if</span> user.posts.any? <span class="hljs-comment"># SELECT 1 FROM posts WHERE user_id = ? LIMIT 1</span>
  ...
<span class="hljs-keyword">end</span>
user.posts.each { ...stuff... } <span class="hljs-comment"># SELECT * FROM posts WHERE user_id = ?</span>
</code></pre>
<p>Forcing the relationship loading with <code>#load</code> is enough to avoid the redundant <code>SELECT</code>.</p>
<pre><code class="lang-ruby">user = User.first
<span class="hljs-keyword">if</span> user.posts.load.any? <span class="hljs-comment"># SELECT * FROM posts WHERE user_id = ?</span>
  ...
<span class="hljs-keyword">end</span>
user.posts.each { ...stuff... } <span class="hljs-comment"># cached: no query</span>
</code></pre>
<p>Further readings on this can be found <a target="_blank" href="https://www.speedshop.co/2019/01/10/three-activerecord-mistakes.html">here</a>.</p>
<h4 id="heading-findeach"><code>find_each</code></h4>
<p>Have you ever been tempted to iterate on a Rails models using <code>#each</code>?
Yeah, that’s cool, but if your database is somewhat large you will see your console explode and your dev machine’s ram disappear in a sneeze.</p>
<p>This is because #each loads the whole table in memory with a <code>SELECT * FROM table</code>, and then iterates one value at a time.
Before starting to iterate it has to fit the whole table, Rails overhead included, inside the memory.
So what’s the correct way to iterate on a large table?</p>
<p>This is where <code>#find_each</code> comes in. This method works exactly as <code>#each</code>, chunking the iteration in 1000-elements batches. It will load and iterate on 1000 elements, empty the ram, and load the next 1000. </p>
<p>The batch size can be controlled by setting the, surprise surprise, <code>batch_size</code> parameter.</p>
<h4 id="heading-database-indexes">Database indexes</h4>
<p>Indexes deserve a long and through discussion, which we will tackle in another article.</p>
<p>Indexes help if you already optimized the queries Rails-side, but the single query still takes too long to complete.
Here are some quick tips.</p>
<p>Put indexes on all field of tables with 1000+ records on which you expect to launch a <code>where</code> or <code>find_by</code>. For example usernames, ids, emails, vat numbers, etc.</p>
<p>Consider that indexes work only in these cases:</p>
<ul>
<li>if the query filters the dataset using equality operators;</li>
<li>if comparison operators on numbers are used, with some limitations, more <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/multiple-column-indexes.html">here</a></li>
<li>if the query is a partial string search, only if the match in on the start of the string, eg: <code>WHERE column LIKE 'something%'</code>, <strong>not</strong> <code>WHERE column LIKE '%something%'</code>.
- 
To check wether a query uses an index you can ask your database to <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/using-explain.html"><code>EXPLAIN</code></a> it:</li>
</ul>
<pre><code class="lang-ruby">Post.where(<span class="hljs-symbol">user_id:</span> <span class="hljs-number">5</span>).explain
<span class="hljs-comment"># =&gt; EXPLAIN (SELECT * from posts [...]) ;</span>
</code></pre>
<p>If you use PostgreSQL you are done, for almost every use case.</p>
<p>If you use MySQL on all tables with 10k+ records create a compound index on all the fields/columns you will search together often.</p>
<p>For example, if this query is run often:</p>
<pre><code class="lang-ruby">User.where(<span class="hljs-symbol">first_name:</span> <span class="hljs-string">'john'</span>, <span class="hljs-symbol">last_name:</span> <span class="hljs-string">'doe'</span>)
</code></pre>
<p>It is a good idea to create a compound index on <code>first_name</code> and <code>last_name</code>:</p>
<pre><code class="lang-ruby">  add_index <span class="hljs-symbol">:users</span>, [<span class="hljs-symbol">:first_name</span>, <span class="hljs-symbol">:last_name</span>]
</code></pre>
<p><strong>Note</strong>: it is nonsense to add an index on a field with a low cardinality, it could do more harm than good (for example an enum fields with a few elements or a boolean).</p>
<h4 id="heading-query-caching">Query caching</h4>
<p>We previously alluded on query caching in a previous paragraph, let’s dig deeper!</p>
<p>If a request is made twice rails does not repeat the query, but serves a cached version of the results.
This can be leveraged in many ways: for example, it makes no sense to make two queries, one after the other, when the second is a filtered version of the first one. It is much better to call again the first query and then filter programmatically.
Concretely, this is bad:</p>
<pre><code class="lang-ruby">users = User.where(<span class="hljs-symbol">role:</span> <span class="hljs-symbol">:admin</span>) <span class="hljs-comment"># first query</span>
users.do_some_stuff
...
users = User.where(<span class="hljs-symbol">role:</span> <span class="hljs-symbol">:admin</span>).where(<span class="hljs-symbol">id:</span> [<span class="hljs-number">10</span>, <span class="hljs-number">50</span>, <span class="hljs-number">100</span>]) <span class="hljs-comment"># this is not cached! you are wasting a query</span>
users.do_some_stuff_again
</code></pre>
<p>This is good:</p>
<pre><code class="lang-ruby">users = User.where(<span class="hljs-symbol">role:</span> <span class="hljs-symbol">:admin</span>) <span class="hljs-comment"># first query</span>
users.do_some_stuff
...
users = User.where(<span class="hljs-symbol">role:</span> <span class="hljs-symbol">:admin</span>).filter { <span class="hljs-params">|e|</span> e.id.<span class="hljs-keyword">in</span>?([<span class="hljs-number">10</span>, <span class="hljs-number">50</span>, <span class="hljs-number">100</span>]) } <span class="hljs-comment"># again the first query, which is cached</span>
users.do_some_stuff_again
</code></pre>
<h4 id="heading-too-large-columns">Too large columns</h4>
<p>Some models may contain particularly heavy columns, like large JSON or TEXT fields.
If these fields are used only in some views it may help to do one of the following:</p>
<h5 id="heading-1-disable-the-column-loading">1. disable the column loading</h5>
<p>In rails a model can be configured to ignore a column, for example: </p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> &lt; ApplicationRecord</span>
  <span class="hljs-keyword">self</span>.ignored_columns = [<span class="hljs-string">'fat_json_column'</span>]
<span class="hljs-keyword">end</span>
</code></pre>
<p>To load it you will need to select it manually with <code>select</code> or <code>pluck</code>:</p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> &lt; ApplicationRecord</span>
  <span class="hljs-keyword">self</span>.ignored_columns = [<span class="hljs-string">'fat_json_column'</span>]
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fat_json_column</span> <span class="hljs-comment"># this is almost like a computed attr</span></span>
    <span class="hljs-comment"># but it loads it from the database</span>
    User.where(<span class="hljs-symbol">id:</span> id).pick(<span class="hljs-symbol">:fat_json_column</span>)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h5 id="heading-2-move-the-field">2. move the field</h5>
<p>The idea is simple: move the large column in another table, with a 1-to-1 relationship with the main table, and then load the relationship when needed:</p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> &lt; ApplicationRecord</span>
  has_one <span class="hljs-symbol">:user_data</span>
<span class="hljs-keyword">end</span>
<span class="hljs-comment"># fat_json_column is here</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserData</span> &lt; ApplicationRecord</span>
  belongs_to <span class="hljs-symbol">:user</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h2 id="heading-whats-next">What’s next?</h2>
<p>We saw how to optimize read queries. The next obvious step is to tackle read queries. See you in the next article of the series!</p>
<h2 id="heading-about-us">About Us</h2>
<p>This article is part of the <a target="_blank" href="https://monade.io">Mònade</a> Developers Blog, written by <a class="user-mention" href="https://hashnode.com/@ProGM">Piero Dotti</a>, edited and translated by <a class="user-mention" href="https://hashnode.com/@melefabrizio">Fabrizio Mele</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Store with Dependency Injection in Vue 2 with Inversify]]></title><description><![CDATA[Here at Mònade we are always open to new creative solutions to improve our workflow and our code. Our current go-to stack is Vue 2 with Typescript, which should point naturally to Vuex as a default reactive store. But Vuex has its drawbacks: its comp...]]></description><link>https://devs.monade.io/store-with-dependency-injection-in-vue-2-with-inversify</link><guid isPermaLink="true">https://devs.monade.io/store-with-dependency-injection-in-vue-2-with-inversify</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[dependency injection]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Fabrizio Mele]]></dc:creator><pubDate>Tue, 19 Apr 2022 07:36:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/RJPEfLuv6Ao/upload/v1649927380373/suEMbCNho.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here at Mònade we are always open to new creative solutions to improve our workflow and our code. Our current go-to stack is Vue 2 with Typescript, which should point naturally to Vuex as a default reactive store. But Vuex has its drawbacks: its complicated, and it has an horrible way to commit actions and mutations (by name, (like php?!))…</p>
<p>In this scenario we came in contact with <strong>Inversify</strong>, a nifty library we are using to fade out mixins as "place where api calls are made". Some time ago we realised that the same library could be also used to inject singletons inside vue components.</p>
<h2 id="heading-the-case">The case</h2>
<p>While scaffolding a new view, a fairly complex one, in a company project, a very complex one, we had to get smart about the business logic of the view: long story short, the view has a big data table showing different records populated from a backend API, and various filters scattered in split panes, modals and whatnot. It seemed a clear case of moving the logic inside the store:</p>
<ul>
<li>the data table watches a getter on the store that returns <code>Model[]</code>;</li>
<li>the various filters update the <code>FilterObject</code> stored inside the store;</li>
<li>the store updates its internal state calling the API with some filter parameters every time the <code>FilterObject</code> is updated.</li>
</ul>
<p>This way the getter returns always a filtered <code>Model</code> and everything is totally decoupled, to allow designers to tinker with the UI without making us dev really unhappy moving around events, wrappers and whatnot.</p>
<h2 id="heading-the-store">The store</h2>
<p>Having some previous knowledge about Inversify container and injections it came to us that it would be much easier to implement and use as a store a singleton service.</p>
<p>The idea is simple: the store is a Typescript class which extends Vue (so it is technically a Vue component, more on this later). The store is bound to the IOC container in singleton scope. The store is injected inside every component which updates the <code>FilterObject</code> or displays the <code>Model[]</code>.
It looks like this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// store.ts</span>

<span class="hljs-keyword">import</span> { inject, injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">"inversify-props"</span>;
<span class="hljs-keyword">import</span> { IAnotherService } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/services/AnotherService"</span>;
<span class="hljs-keyword">import</span> { SYMBOLS } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app.container"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> IStore <span class="hljs-keyword">extends</span> Vue {
  get items(): Model[];

  set items(items: Model[]);

  get filters(): FilterObject;

  set filters(filters: FilterObject);

}

<span class="hljs-meta">@injectable</span>() <span class="hljs-comment">// Inversify here</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Store <span class="hljs-keyword">extends</span> Vue <span class="hljs-keyword">implements</span> IStore {
  _items: Model[] = [];
  _filters: FilterObject = {};

  <span class="hljs-keyword">private</span> anotherService!: IAnotherService;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"> <span class="hljs-comment">// Constructor injection with Inversify</span>
    <span class="hljs-meta">@inject</span>(SYMBOLS.AnotherService) anotherService: IAnotherService
  </span>) {
    <span class="hljs-built_in">this</span>.anotherService = anotherService;
  }

  set items(items: Model[]) {
    <span class="hljs-built_in">this</span>._items = items;
    <span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'items-updated'</span>, <span class="hljs-built_in">this</span>._items); <span class="hljs-comment">// Vue!</span>
  }

  get items(): Model[] {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._items;
  }

  get filters() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._filters;
  }

  set filters(filters: FilterObject) {
    <span class="hljs-built_in">this</span>._filters = filters;
    <span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'filters-updated'</span>, <span class="hljs-built_in">this</span>._filters); <span class="hljs-comment">// More Vue!</span>

    <span class="hljs-built_in">this</span>.updateItems();
  }

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> updateItems() {
    <span class="hljs-built_in">this</span>.items = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.anotherService.findSomeModels(<span class="hljs-built_in">this</span>.filters);
  }

  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Glossing over missing type declarations its working are quite simple: we leverage Typescript getters and setters to react to attribute updates: every time a the filter is updated we advertise the filter update event and then call the API (hopefully with a debouncer). The API call will update the items attribute and advertise the fact that the items may have changed.</p>
<p>Extending Vue (i.e. declaring the store as a Vue component) allows us to leverage Vue events to advertise stuff! Event bus baby! (line 31)</p>
<p>Now we just need to:</p>
<ol>
<li>singleton this class with more Inversify</li>
<li>subscribe to relevant events from the view components.</li>
</ol>
<h2 id="heading-the-container">The container</h2>
<p>Now we need to bind our shiny new <code>Store</code> to the container. Here we encountered some roadblocks, but it turns out it was a bad written guide!</p>
<p>In the <code>main.ts</code> where we declare and mount the Vue instance we must initialise the dependency container. Not that <code>reflect-metadata</code> is imported before everything else. Weird errors could be thrown otherwise.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// main.ts</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"reflect-metadata"</span>;
<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">import</span> buildDependencyContainer <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app.container"</span>;

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

buildDependencyContainer();

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

<span class="hljs-keyword">new</span> Vue({}).$mount(<span class="hljs-string">"#app"</span>);
</code></pre>
<p>not before building the container:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app.container.ts</span>

<span class="hljs-keyword">import</span> { container } <span class="hljs-keyword">from</span> <span class="hljs-string">"inversify-props"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SYMBOLS = {
  AnotherService: <span class="hljs-built_in">Symbol</span>.for(<span class="hljs-string">"IAnotherService"</span>),
  Store: <span class="hljs-built_in">Symbol</span>.for(<span class="hljs-string">"IStore"</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">buildDependencyContainer</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span> </span>{
  container
    .bind&lt;IAnotherService&gt;(SYMBOLS.AnotherService)
    .to(AnotherService)
    .inTransientScope();
  container
    .bind&lt;IStore&gt;(SYMBOLS.Store)
    .to(Store)
    .inSingletonScope(); <span class="hljs-comment">// Singleton is the keyword here</span>
}
</code></pre>
<p>This functions makes a bit clearer the <code>@inject</code> syntax found in the <code>Store.ts</code>. We will anyway see more on that just now. Note that the Store is declared in singleton scope: this means that it will be instantiated just once. Everyone asking for the Store object anywhere in the single page application will get the same instance, allowing us to use it as a store!</p>
<h2 id="heading-the-components">The components</h2>
<p>Now that we have a IOC container and some injectable stuff fired up and running we can do fancy stuff without anything more than an <code>@inject</code> decorator.
For example, a component updating the filter could be:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// SearchBox.vue</span>
&lt;template&gt;
  &lt;div&gt;
    &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> v-model=<span class="hljs-string">"term"</span> /&gt;
  &lt;div&gt;
&lt;/template&gt;
&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { Vue, Component, Watch } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue-property-decorators"</span>;
<span class="hljs-keyword">import</span> { inject } <span class="hljs-keyword">from</span> <span class="hljs-string">"inversify-props"</span>;
<span class="hljs-keyword">import</span> { SYMBOLS } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app.container"</span>;
<span class="hljs-keyword">import</span> { IStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/services/Store"</span>;
<span class="hljs-meta">@Component</span>({})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">class</span> SearchBox <span class="hljs-keyword">extends</span> Vue {
  <span class="hljs-meta">@inject</span>(SYMBOLS.Store) <span class="hljs-keyword">readonly</span> store!: IStore;

  term = <span class="hljs-string">""</span>;

  mounted() {
    <span class="hljs-built_in">this</span>.updateTerm();
    <span class="hljs-built_in">this</span>.store.$on(<span class="hljs-string">'filter-updated'</span>, <span class="hljs-built_in">this</span>.updateTerm);
  }

  updateTerm() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.store?.filter?.term != <span class="hljs-built_in">this</span>.term) {
      <span class="hljs-built_in">this</span>.term = <span class="hljs-built_in">this</span>.store?.filter?.term ?? <span class="hljs-string">""</span>;
    }
  }

  <span class="hljs-meta">@Watch</span>(<span class="hljs-string">"term"</span>)
  onTermUpdated() {
    <span class="hljs-built_in">this</span>.store.filters = <span class="hljs-built_in">Object</span>.assign(
        {},
        <span class="hljs-built_in">this</span>.store.filters,
        { term: <span class="hljs-built_in">this</span>.term }
     );
  }
}
&lt;/script&gt;
</code></pre>
<p>Vue <code>on</code> and <code>off</code> methods can be used to hook into the store events. This <code>SearchBox</code> components can be dropped anywhere on a view and it will always be synchronised with the store singleton.
Note that the store is injected with a decorator, it is possible to manually get it from the container by calling <code>container.get</code> inside <code>mounted</code>. I find decorators much more elegant and concise.
On the other side, with some imagination we can image this component dynamically refreshing its contents as the store updates its state:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// DataDisplay.vue</span>
&lt;template&gt;
  &lt;div&gt;
    &lt;span
      v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"item in items"</span>
    &gt;{{ item }}&lt;
    /span&gt;
  &lt;div&gt;
&lt;/template&gt;
&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { Vue, Component } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue-property-decorators"</span>;
<span class="hljs-keyword">import</span> { inject } <span class="hljs-keyword">from</span> <span class="hljs-string">"inversify-props"</span>;
<span class="hljs-keyword">import</span> { SYMBOLS } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app.container"</span>;
<span class="hljs-keyword">import</span> { IStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/services/Store"</span>;
<span class="hljs-meta">@Component</span>({})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">class</span> DataDisplay <span class="hljs-keyword">extends</span> Vue {
  <span class="hljs-meta">@inject</span>(SYMBOLS.Store) <span class="hljs-keyword">readonly</span> store!: IStore;

  items: <span class="hljs-built_in">any</span>[] = [];

  mounted() {
    <span class="hljs-built_in">this</span>.updateTerm();
    <span class="hljs-built_in">this</span>.store.$on(<span class="hljs-string">'items-updated'</span>, <span class="hljs-built_in">this</span>.updateItems);
  }

  updateTerm(items: <span class="hljs-built_in">any</span>[]) { <span class="hljs-comment">// Note that being a Vue event there's a payload</span>
    <span class="hljs-built_in">this</span>.items = items;
  }
}
&lt;/script&gt;
</code></pre>
<p>Even more quick and easy. Just subscribe to the <code>items-updated</code> event and the component will (not so) magically be synchronised with the search box.</p>
<h2 id="heading-conclusions">Conclusions</h2>
<p>Obviously this is a very simple example, but it should satisfy the need to se a complete example of Inversify DI in actions with prop injection in class components.</p>
<p>The store could contain more logic and even actions (as simple methods), even if we prefer to keep inside it the logic strictly related to items searching and filtering. Adding stuff to it just because it’s easy and it works can cause “big store syndrome”.</p>
<p>There are obviously limitations: for one any persistence must be done by hand. We did not yet encounter this requirement, as this is mostly a runtime support for a view. Also, no mutations mean no history and rollbacks, so this is not the thing you are looking for if you need an action history.</p>
]]></content:encoded></item></channel></rss>