<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thanh Minh</title>
    <description>The latest articles on DEV Community by Thanh Minh (@thanhlm).</description>
    <link>https://dev.to/thanhlm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F605978%2F60384c72-76a2-4ce6-8e48-af8d6a520661.jpeg</url>
      <title>DEV Community: Thanh Minh</title>
      <link>https://dev.to/thanhlm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thanhlm"/>
    <language>en</language>
    <item>
      <title>Boost NextJS TTI &amp; FID performance without compromise and pain</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Wed, 08 Jun 2022 07:22:52 +0000</pubDate>
      <link>https://dev.to/thanhlm/boost-nextjs-tti-fid-performance-without-compromise-and-pain-5h0n</link>
      <guid>https://dev.to/thanhlm/boost-nextjs-tti-fid-performance-without-compromise-and-pain-5h0n</guid>
      <description>&lt;h2&gt;
  
  
  Why should you read this blog?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;As the title said: “Boost NextJS TTI &amp;amp; FID performance without compromise and pain”&lt;/li&gt;
&lt;li&gt;Islands Architectures for Nextjs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sjm61mo4u0pf7s2ipsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sjm61mo4u0pf7s2ipsm.png" alt="Before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://next-lazy-hydrate-origin.vercel.app/" rel="noopener noreferrer"&gt;https://next-lazy-hydrate-origin.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pagespeed.web.dev/report?url=https%3A%2F%2Fnext-lazy-hydrate-origin.vercel.app%2F&amp;amp;form_factor=mobile" rel="noopener noreferrer"&gt;Live check PageSpeed&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhf2ut4mivz3dyfyln3u3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhf2ut4mivz3dyfyln3u3.png" alt="After"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://next-lazy-hydrate-optimized.vercel.app/" rel="noopener noreferrer"&gt;https://next-lazy-hydrate-optimized.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pagespeed.web.dev/report?url=https%3A%2F%2Fnext-lazy-hydrate-optimized.vercel.app%2F&amp;amp;form_factor=mobile" rel="noopener noreferrer"&gt;Live check PageSpeed&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hydrating is PURE OVERHEAD
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.builder.io/blog/hydration-is-pure-overhead" rel="noopener noreferrer"&gt;Hydration is Pure Overhead&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzsezzk3rl9b6rxo4hne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzsezzk3rl9b6rxo4hne.png" alt="SSR process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As described in the post above, &lt;code&gt;Hydration&lt;/code&gt; progress is PURE OVERHEAD since you need to load the code and render the component twice.&lt;/p&gt;

&lt;p&gt;Imagine you have a very long landing page built by Nextjs and most of it is a static component, then when you hit the Enter in the URL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTML contains all your landing page content sent to the browser (Which is the result of SSR)&lt;/li&gt;
&lt;li&gt;JavaScript is downloaded to the browser, get parsed, and executed (Most of it contains text content only which is nearly the same as your HTML)&lt;/li&gt;
&lt;li&gt;Which Javascript downloaded, now it attaches events to the DOM. Now your website is fully usable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second moves make most of SSR page has TTI (Time To Interactive) and FID (First Input Delay) so high&lt;/p&gt;
&lt;h2&gt;
  
  
  Progressive Hydration
&lt;/h2&gt;

&lt;p&gt;Let’s take a step to optimize our long-landing-page. Because on our landing page, most of the component is static (Only text and image, nothing much called “interactive”) so it’s a waste of time to hydrate those components. What if we disable hydrate for some components or only hydrate components when it’s in the &lt;code&gt;Viewport&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F065v77zaxjmam3pn5hnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F065v77zaxjmam3pn5hnx.png" alt="Progressive Hydration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can easily archive using &lt;code&gt;react-hydration-on-demand&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;withHydrationOnDemand&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-hydration-on-demand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../Card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Hydrate when the component enters the viewport&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CardWithHydrationOnDemand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withHydrationOnDemand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})(&lt;/span&gt;
    &lt;span class="nx"&gt;Card&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CardWithHydrationOnDemand&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"my card"&lt;/span&gt;
                &lt;span class="na"&gt;wrapperProps&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;customClassName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can optimize the 3rd bullet - Reduce the time JavaScript executed to hydrate our landing page. Good job!&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy load component code and hydrate when needed
&lt;/h2&gt;

&lt;p&gt;We can save some executed time using &lt;code&gt;react-hydration-on-demand&lt;/code&gt; but we still have lots of redundancy code here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaScript of those components is still downloaded and parsed, it just doesn’t get executed.&lt;br&gt;
Do we have any way to fully render the HTML of the website but only load the component’s JS only when needed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is an answer for that: &lt;a href="https://www.patterns.dev/posts/islands-architecture/" rel="noopener noreferrer"&gt;https://www.patterns.dev/posts/islands-architecture/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i6ivpizq0offul6wl6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i6ivpizq0offul6wl6h.png" alt="Islands Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is quite simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully render HTML in SSR&lt;/li&gt;
&lt;li&gt;Load a really minimum of JavaScript to listen to the events&lt;/li&gt;
&lt;li&gt;If an event is fired, load the JS related to it and executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solution comes with a huge performance boost by scarifying a little time between every user’s interactive. But I do think it worse doing so 🌟&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e4dpbsjux20hrnokflt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e4dpbsjux20hrnokflt.png" alt="Disable Javascript reduces the TTI more than 7 times. What if we can remove half of it?&amp;lt;br&amp;gt;
"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disable Javascript reduces the TTI more than 7 times. What if we can remove half of it?&lt;/p&gt;

&lt;p&gt;This is nice! The solution is simple but quite hard to do. Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Because Reactjs only supports hydrating a full application (&lt;a href="https://github.com/reactwg/react-18/discussions/37" rel="noopener noreferrer"&gt;It will be solved when v18 is fully implemented&lt;/a&gt;). The &lt;code&gt;react-hydration-on-demand&lt;/code&gt; actually do some trick to skip the hydrating process&lt;/li&gt;
&lt;li&gt;In Nextjs, if the component is defined as &lt;code&gt;dynamic&lt;/code&gt; and it renders in SSR, its JS also gets sent to the browser right away so nothing called &lt;code&gt;lazy&lt;/code&gt; here&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.builder.io/blog/why-progressive-hydration-is-harder-than-you-think" rel="noopener noreferrer"&gt;Why Progressive Hydration is Harder than You Think&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I make a package that can&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Skip the component hydrating process. Heavily based on &lt;code&gt;react-hydration-on-demand&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove the JS from the bundle and make you control when the JS is loaded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How can I do this trick? &lt;a href="https://github.com/thanhlmm/next-lazy-hydrate/blob/main/src/index.tsx" rel="noopener noreferrer"&gt;Check it out&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the result&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/718200286" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;next-lazy-hydrate
yarn add next-lazy-hydrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;lazyHydrate&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-lazy-hydrate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Static component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WhyUs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazyHydrate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/whyus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Lazy hydrate when users hover the component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazyHydrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hover&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HomePage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AboveTheFoldComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ----The Fold---- */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WhyUs&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Document&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/thanhlmm/next-lazy-hydrate" rel="noopener noreferrer"&gt;https://github.com/thanhlmm/next-lazy-hydrate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The API is quite simple, I’d love to see how this package can help you &lt;strong&gt;Boost NextJS TTI &amp;amp; FID performance without compromise and pain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Original post: &lt;a href="https://thanhle.blog/en/blog/boost-nextjs-tti-fid-performance-without-compromise-and-pain" rel="noopener noreferrer"&gt;https://thanhle.blog/en/blog/boost-nextjs-tti-fid-performance-without-compromise-and-pain&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>performance</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Frontend performance pattern</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Fri, 18 Feb 2022 03:57:41 +0000</pubDate>
      <link>https://dev.to/thanhlm/frontend-performance-pattern-19o7</link>
      <guid>https://dev.to/thanhlm/frontend-performance-pattern-19o7</guid>
      <description>&lt;p&gt;Original post: &lt;a href="https://thanhle.blog/blog/frontend-performance-pattern-en" rel="noopener noreferrer"&gt;https://thanhle.blog/blog/frontend-performance-pattern-en&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you read this?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Common patterns use to optimize frontend performance&lt;/li&gt;
&lt;li&gt;Boost your web app speed&lt;/li&gt;
&lt;li&gt;Convince your boss and colleague&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When should I care about performance?
&lt;/h2&gt;

&lt;p&gt;First of all, let’s make an agreement that whenever we design a system, structure for an app, it means that we’re making trade-offs. We cut some parts to gain others in order to make the system fit with the problem. What if we want all? It’s impossible, because resources when kick off the project is always limited, however, the problem on the opposite can grow endlessly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralize vs Decentralize&lt;/li&gt;
&lt;li&gt;Monolithic vs Microservice&lt;/li&gt;
&lt;li&gt;SSR vs CSR&lt;/li&gt;
&lt;li&gt;OOP vs FP&lt;/li&gt;
&lt;li&gt;SQL vs No-SQL&lt;/li&gt;
&lt;li&gt;Language X vs Language Y&lt;/li&gt;
&lt;li&gt;API vs GraphQL&lt;/li&gt;
&lt;li&gt;Stream vs Batch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then when should I care about performance? And which is the trade-off?&lt;/p&gt;

&lt;p&gt;For me, a frontend app has to maintain 3 aspects&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functional - Your app must run with correct logic&lt;/li&gt;
&lt;li&gt;Maintainable/Readable - If it run right, then it should be easy to maintain and add a new feature&lt;/li&gt;
&lt;li&gt;Performance - it should be fast, delight the user journey&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Functional is easy to understand, it is the only aspect that we can not make a trade-off. Then now, our application becomes a slider between &lt;code&gt;clean code&lt;/code&gt; vs &lt;code&gt;performance&lt;/code&gt;, it’s depended on each project and the problem to trade-off&lt;/p&gt;

&lt;p&gt;🐣 You are a guy in the project, so you have the right to know which is more important? Do you want to launch many features at a fast pace or do you want the feature is running lighting fast?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I was really obsessing with performance and had a chance to see that many juniors got the same obsession as me.  Once upon a time, I spend a day paralleling a script that validates the CSV file. The optimization looks good, reduce the time from 15 minutes to 4 minutes. Sadly, the script run only 1 time a week and in turn, it can only save about 40 minutes a month on a free server&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Performance pattern
&lt;/h2&gt;

&lt;p&gt;Here are some common patterns used to optimize performance. And because it is quite popular so it’s quite easy to apply for your project which our sacrifice much on &lt;code&gt;Maintainenable/Readable&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Split code/Lazyload
&lt;/h3&gt;

&lt;p&gt;Difficulty: Easy&lt;/p&gt;

&lt;p&gt;When to apply: As soon as the project start, we can start with a simple one like split code by pages/routes. After that, if you want to take this further, you can split the code by user interaction&lt;a href="https://thanhle.blog/vi/blog/lazy-load-hieu-qua-de-toi-ui-trang-web-hon" rel="noopener noreferrer"&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spell: Only load what users need&lt;/p&gt;

&lt;p&gt;How: It depends on your framework, so search Google with this formula: &lt;code&gt;Framework + code splitting&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example on React&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/code-splitting.html" rel="noopener noreferrer"&gt;Code-Splitting - React&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OtherComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./OtherComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OtherComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prevent installing the duplicated lib
&lt;/h3&gt;

&lt;p&gt;Difficulty: Quite Easy&lt;/p&gt;

&lt;p&gt;When to apply: When you start thinking about installing a new library. Then we have 3 options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you use existing lib, pray it to fit with your problem&lt;/li&gt;
&lt;li&gt;If you use new lib, change the legacy code, and pray it to fit with the legacy problem, testing for regression bugs&lt;/li&gt;
&lt;li&gt;Use both libs ⇒ ONLY this is your last hope... like your PM is hanging a knife on your neck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my current project, we have 3 libraries to handle date-time: &lt;code&gt;momment&lt;/code&gt;, &lt;code&gt;date-fns&lt;/code&gt; và &lt;code&gt;dayjs&lt;/code&gt; . Which &lt;code&gt;moment&lt;/code&gt; and &lt;code&gt;date-fns&lt;/code&gt; is big bundle size. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/dmtrkovalenko/you-might-not-need-date-fns-23f7"&gt;You might not need date-fns&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spell: Check packages.json before searching/installing new libraries&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose the library that supported ES6 and tree shaking
&lt;/h3&gt;

&lt;p&gt;Difficulty: Easy, but depends on community&lt;/p&gt;

&lt;p&gt;When to apply: All the time. Bundle size and tree shaking support should be important points to consider.&lt;/p&gt;

&lt;p&gt;Spell: The newer library the more chance it is better (But it does not guarantee that it is stable and correctly)&lt;/p&gt;

&lt;p&gt;How: Check library on &lt;a href="https://bundlephobia.com/" rel="noopener noreferrer"&gt;https://bundlephobia.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0p60t56cps0tiam1qot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0p60t56cps0tiam1qot.png" alt=" raw `redux` endraw  bundle size is 1.6kB when Gzip and supported tree-shaking"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;redux&lt;/code&gt; bundle size is 1.6kB when Gzip and supported tree-shaking&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mui.com/guides/minimizing-bundle-size/" rel="noopener noreferrer"&gt;Minimizing bundle size - MUI&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Debounce user input
&lt;/h3&gt;

&lt;p&gt;Difficulty: Quite easy&lt;/p&gt;

&lt;p&gt;When to apply: When we’re hooking user typing, scrolling event which some tasks&lt;/p&gt;

&lt;p&gt;Spell: Search input ⇒ Debounce&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/fundamentals/performance/rendering/debounce-your-input-handlers" rel="noopener noreferrer"&gt;Debounce Your Input Handlers | Web Fundamentals | Google Developers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In more advantage cases, we can use debounce for API response. A common case is to debounce the response for trading/order book on weak computers&lt;/p&gt;

&lt;h3&gt;
  
  
  Add &lt;code&gt;loading=lazy&lt;/code&gt; for tag &lt;code&gt;img&lt;/code&gt;, &lt;code&gt;iframe&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Difficulty: Easy&lt;/p&gt;

&lt;p&gt;When to apply: Most of the time you see &lt;code&gt;img&lt;/code&gt; tag, unless you are sure that the &lt;code&gt;img&lt;/code&gt; is above the fold&lt;/p&gt;

&lt;p&gt;Spell: Image + &lt;code&gt;loading=lazy&lt;/code&gt; ⇒ ✈️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3k75axhoh7ibrtnx0czo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3k75axhoh7ibrtnx0czo.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://www.notion.so/image/https:%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Feed374b2-19d1-444a-b21a-ee686940bb30%2FScreen_Shot_2022-01-21_at_12.45.19_PM.png?table=block&amp;amp;id=a6b45670-a7e6-40bc-ba3d-db40424d6a91&amp;amp;cache=v2"&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Nimbus"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Memorized function
&lt;/h3&gt;

&lt;p&gt;Difficulty: Normal&lt;/p&gt;

&lt;p&gt;When to apply: When your function drain lots of CPU and RAM&lt;/p&gt;

&lt;p&gt;Spell: Cache the expensive task&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/understanding-memoize-in-javascript-51d07d19430e/" rel="noopener noreferrer"&gt;How to use Memoize to cache JavaScript function results and speed up your code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition, you can use Web Worker to push those computations into background processes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// CPU intensive task here&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cache frontend assets using Service Worker
&lt;/h3&gt;

&lt;p&gt;Difficulty: Normal, hard. It’s quite hard when starting but the result is worst it&lt;/p&gt;

&lt;p&gt;When to apply: When you are working in a really big app, bundle size is huge likes complex Admin/CRM&lt;/p&gt;

&lt;p&gt;Spell: Complex, big web app ⇒ Service Worker&lt;/p&gt;

&lt;p&gt;Example in React&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/noconsulate/react-pwa-with-workbox-6dl"&gt;React PWA with Workbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Trust me, after you have done this, users will only ever see the loading indicator for the beginning. After that, you can update the app in the background. I will go into detail about how I do it in another post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual list
&lt;/h3&gt;

&lt;p&gt;Difficulty: Hard&lt;/p&gt;

&lt;p&gt;When to apply: When you have a list containing lots of items. Users have to scroll a while to view all items&lt;/p&gt;

&lt;p&gt;Spell: You have a table more than 100 items, you are building something like feed on Facebook, Twitter ⇒ Virtual list&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react-virtual.tanstack.com/" rel="noopener noreferrer"&gt;React Virtual&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I highly recommend this one. Supper power and lightweight. Forget outdated &lt;code&gt;react-window&lt;/code&gt;, &lt;code&gt;react-virutalize&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;When working with &lt;code&gt;Virtual list&lt;/code&gt;, developers should know about the concept how it works, and also when the component is rerendered to take full power from it. If not, you’re shooting on your foot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/xvqIOHfQvth5NeoT0Y/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/xvqIOHfQvth5NeoT0Y/giphy.gif" alt="https://media.giphy.com/media/xvqIOHfQvth5NeoT0Y/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Break long-run functions into multiple short-run functions
&lt;/h3&gt;

&lt;p&gt;Difficulty: Hard&lt;/p&gt;

&lt;p&gt;When to apply: When you run the function, and your laptop hangs 🙃&lt;/p&gt;

&lt;p&gt;Spell: Like Above&lt;/p&gt;

&lt;p&gt;How: You break your long-run, CPU-bound  function into multiple short-run functions with &lt;code&gt;setTimeOut&lt;/code&gt; ,&lt;code&gt;requestAnimationFrame&lt;/code&gt;. However, when breaking long-run functions into many small ones is not an easy task, sometimes your need to keep those functions running sequentially to make sure the function is always correct&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimistic update
&lt;/h3&gt;

&lt;p&gt;Difficulty: Easy, normal, hard&lt;/p&gt;

&lt;p&gt;Easy when you apply for simple entity&lt;/p&gt;

&lt;p&gt;Normal when those entities start conflicting with local and server and you need to solve the conflict&lt;/p&gt;

&lt;p&gt;Hard when the logic is quite complex and you have also to deal with solving the conflict on local state and server state&lt;/p&gt;

&lt;p&gt;For eg: The like button is easy, the comment is normal, and posting a status is a really hard case&lt;/p&gt;

&lt;p&gt;When to apply: When the feature is quite simple. The success rate of the API is about 99.99%&lt;/p&gt;

&lt;p&gt;Spell: Simple logic, 99.99% success ⇒ Optimistic update&lt;/p&gt;

&lt;p&gt;&lt;a href="https://derekndavis.com/posts/lightning-fast-front-end-build-optimistic-ui" rel="noopener noreferrer"&gt;Cheat Code for a Lightning Fast Front End: Building an Optimistic UI&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lazy polyfill/Dynamic polyfill
&lt;/h3&gt;

&lt;p&gt;Difficulty: Normal, hard&lt;/p&gt;

&lt;p&gt;When to apply: When you’re too tired, don’t have any other option to optimize&lt;/p&gt;

&lt;p&gt;Spell: When you see that the polyfill bundle size is quite huge but users are all high-tech&lt;/p&gt;

&lt;p&gt;How: Leading right now is Polyfill.io. However, it is quite hard because you need to know how to set up in both frontend and backend&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Which is the pattern that you use to optimize performance? let me know, I’m excited to explore more&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>performance</category>
      <category>react</category>
    </item>
    <item>
      <title>Write lean state-management</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Tue, 14 Dec 2021 10:37:24 +0000</pubDate>
      <link>https://dev.to/thanhlm/write-lean-state-management-31le</link>
      <guid>https://dev.to/thanhlm/write-lean-state-management-31le</guid>
      <description>&lt;p&gt;Original post: &lt;a href="https://thanhle.blog/blog/write-lean-state-management"&gt;https://thanhle.blog/blog/write-lean-state-management&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why should you read this article?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Improve your level of state management&lt;/li&gt;
&lt;li&gt;Code state in a leaner way&lt;/li&gt;
&lt;li&gt;There is another way to approach the problem on the frontend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had a chance to meet a few friends when they first started working as a frontend and I found that most of them had the same problem: Writing logic in state management was too complicated, leading to code that was both confusing and difficult to debug.&lt;br&gt;
Usually, after such reviews, I'm the guy who deletes all that code to have a leaner version, so hopefully, through this article, everyone will learn a few skills when writing state-management code.&lt;/p&gt;


⚠️ In the context of this post, I will only focus on most of the Frontend frameworks today (React, Vue, Sveltve, Angular,...) Usually, I use React as an example, but most of the others will be similar. because [state management is framework independent](https://thanhle.blog/blog/guide-to-choosing-state-management-library-for-your-next-project)


&lt;h2&gt;
  
  
  UI = f(state)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lC_bA1uA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3tdl4qlthoqkn970iech.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lC_bA1uA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3tdl4qlthoqkn970iech.png" alt="Legendary Formula for Frontend Developer" width="762" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Legendary Formula for Frontend Developer&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;State - the particular condition that someone or something is in at a specific time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cambridge&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a nutshell, the state of your application will be mapped through the respective UI through a mapping function. So, clean state management (now called clean state management) means designing the state in the application in a neat way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mapping via UI is easier ‍💨&lt;/li&gt;
&lt;li&gt;Less code means fewer bugs  🐹&lt;/li&gt;
&lt;li&gt;Less code means easier to maintain 😌&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  When does the state change?
&lt;/h2&gt;

&lt;p&gt;To write a clean state, you must first find out what causes the state to change&lt;/p&gt;

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

&lt;p&gt;In an application, there are 2 things that can change your state&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event from user interactive with App&lt;/li&gt;
&lt;li&gt;Event from 3rd party (Here I define everything that triggers events into the app that doesn't come from the user as 3rd party, it can be a response from backend, an event from WebSocket, or... power outage, network failure. )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Normally, the flow of writing the state that I often see will follow a structure like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Event is triggered (User or 3rd party)&lt;/li&gt;
&lt;li&gt;The code that handles that event get called&lt;/li&gt;
&lt;li&gt;Save the processed data to state&lt;/li&gt;
&lt;li&gt;UI render according to the new state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is possible to re-example that flow in the case: Filter the list of Done tasks as follows&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User triggers filter done task&lt;/li&gt;
&lt;li&gt;Get event from user, filter the done task&lt;/li&gt;
&lt;li&gt;Save the result into state&lt;/li&gt;
&lt;li&gt;Render result into the UI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;If people learn about the data maker, it will call this flow: ETL - (Extract - Transform - Load). You Extract data from the event, transform it into the required data, then load it into the state&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;ETL explained&lt;/p&gt;
&lt;h2&gt;
  
  
  What's the problem with doing ETL in the front-end?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;When there are multiple events combined to produce the same UI output.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine with the original Todo list example, I need to do more Search todo list features. Now our state will be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="c1"&gt;// List todo raw&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Undone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keyword&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since most of the software build process will follow Agile, which means creating incremental by each iteration, the case of completing the todo list with the Done/Undone filter and then adding the feature search todo is a common thing ☺️  . Don't blame any guy for not telling you to do it from the beginning.&lt;/p&gt;

&lt;p&gt;Now you will see it is quite simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When users inputs search keyword&lt;/li&gt;
&lt;li&gt;Get the source data, filter by status, then filter again by keyword&lt;/li&gt;
&lt;li&gt;Then save it back to the state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now Todo list will have the following 2 flows&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--udQ439ST--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xa7nnar75juaznjbutae.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--udQ439ST--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xa7nnar75juaznjbutae.jpeg" alt="Image description" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you see the problem here? Flow &lt;code&gt;filter by status&lt;/code&gt; will be wrong because it only &lt;code&gt;filter by status&lt;/code&gt; and drops &lt;code&gt;filter by keyword&lt;/code&gt;. You are new to the project, you only know the task to do is add more flow search by keyword, but you do not know that the old flows also change the output when adding a new state this is also understandable! You only care the flow you just did: Search by keyword!&lt;/p&gt;

&lt;p&gt;Ok, I saw the bug 🤡 so now it's good to combine it into a function. After that, if you need to add &lt;code&gt;filter by XYZ&lt;/code&gt;, put it in that function and it's done, how many QA guys come in and poke 😎.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j18Hro3R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa82uz3zhoe5zt8bq3qp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j18Hro3R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa82uz3zhoe5zt8bq3qp.png" alt="Image description" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No, not that easy! Now add a case like this: In addition to the filtered todo list as required above, the user also wants to have an additional list containing only the todos whose priority is &lt;code&gt;Important&lt;/code&gt;.&lt;br&gt;
I'll call the flow I've been working on is &lt;code&gt;flow 1&lt;/code&gt; and the flow we gonna do next is &lt;code&gt;flow 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now the flow code will look like in the picture. You need to calculate a new list to filter by priority according to the filtered results, there are 2 ways:&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Run the transform function again in the &lt;code&gt;flow 1&lt;/code&gt;. The downside is that this transform function has to be run twice&lt;/li&gt;
&lt;li&gt;Get the results in State 1for further calculation. The downside is that your app will have to re-render 2 times, first rendering according to the first flow, then getting the results from state 1, and then running again with flow 2 leading to the 2nd rendering to get the desired results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🚫 Don't try to attach Filter by Priority to &lt;code&gt;flow 1&lt;/code&gt; and always produce &lt;code&gt;state 1&lt;/code&gt; and &lt;code&gt;state 2&lt;/code&gt; because doing so will make your app even more confusing 🙃 because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code is not self-explanatory to show the flow of the app well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow expects will be described: Get the output of the &lt;code&gt;flow 1&lt;/code&gt;, filter by priority to get the &lt;code&gt;flow 2&lt;/code&gt; output. However, if you look at the code you combine both detailed processing of flow 1 and detailed processing of flow 2 into one function. Please don't&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;A good flow is one that clearly shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the required &lt;strong&gt;input&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What is the desired &lt;strong&gt;output&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When&lt;/strong&gt; will this flow be run&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The problem in general
&lt;/h2&gt;

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

&lt;p&gt;In general, you are handling the event independently, and for &lt;strong&gt;each UI need, you save a separate state for it&lt;/strong&gt;. Doing so makes your code more difficult to extend, and also has to save more state like the example I mentioned earlier, but the more code, the more bugs 🐞&lt;/p&gt;

&lt;h2&gt;
  
  
  A better way with ELT (Extract - Load - Transform)
&lt;/h2&gt;

&lt;p&gt;Now let's try to flip the steps between load and transform. Instead of transforming and then load it to the state, we can do the opposite. Load the state first and then transform it to render the UI&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tRwDFtFK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pjm6f0clul60i73zx00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tRwDFtFK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pjm6f0clul60i73zx00.png" alt="Image description" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, have you noticed that our state is a billion times more compact? By changing the order of running the flow, namely the transform to the last step and then taking that output to render to the UI, I don't need to save anything.&lt;/p&gt;

&lt;p&gt;Let's go back to the original example and see it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Flow 1&lt;/code&gt;, when users trigger an event filter by status or filter by keyword, save event data status or keyword into the state. Then there is a transform function with input as

&lt;ul&gt;
&lt;li&gt;Source data&lt;/li&gt;
&lt;li&gt;Status&lt;/li&gt;
&lt;li&gt;Keyword&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time one of the 3 inputs of the state above changes, the render function will run again transform function will calculate new result UI is updated&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Flow 2&lt;/code&gt;, when the user has an event filter by priority. There will be a transform function corresponding to the input

&lt;ul&gt;
&lt;li&gt;Priority&lt;/li&gt;
&lt;li&gt;The output of transform function in the &lt;code&gt;flow 1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Very clear without sacrificing performance right?&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance? Every time the app renders, does the transform function rerun as well?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As I said above, the state of the app only changes when an event is fired. So whether you run the transform function when there is an event and then save the result to the state or save the state and run the transform, it makes no difference, you have to run the transform again. &lt;/p&gt;

&lt;p&gt;So what if an unrelated event causes the component to re-render ⇒ it has to run the transform function again while the input of that transform function doesn't change anything?&lt;/p&gt;

&lt;p&gt;I find it's easy to fix if you use it &lt;code&gt;react&lt;/code&gt;, put it in &lt;code&gt;useMemo&lt;/code&gt;with the dependencies as the list &lt;code&gt;input&lt;/code&gt;of the transform, in &lt;code&gt;vue&lt;/code&gt; it's even more easier, just put it into &lt;code&gt;computed&lt;/code&gt;  and now you done. If you use other frameworks, the keyword to solve is &lt;code&gt;memorized function&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Is it possible to scale in a large application?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, absolutely! Imagine that source data is unique - a source of trust, any component that consumes data will have a different way of looking at that data.&lt;/p&gt;

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

&lt;p&gt;For eg: Todo list is the source of trust that is saved from the backend. The Todo component will filter from that source of trust Undone tasks. The history component will filter from that source of trust past tasks.&lt;/p&gt;

&lt;p&gt;So each component will have a different way of viewing data, and that view will, along with the component's lifecycle, be created when the component is created and deleted when the component is destroyed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;isloading&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;To put it simply, there are 2 events that will change &lt;code&gt;isLoading&lt;/code&gt;. The first is the user triggering request, and the other is when the response returns the result. This is a sub-state to represent the UI. And certainly, this type must be saved, but this type of state usually has nothing to do with other UI outputs, so I'm still ok when I put it in the state. Actually, I don't know any other way to handle these cases&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;State normalization is better?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Actually, it's not very relevant, state normalization is a way to deal with redundancy in the state. So it blends well with ELT. Now the flow will be &lt;strong&gt;ETLT&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extract -&lt;/strong&gt; data from API (Run once)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transform&lt;/strong&gt; - normalize data (Run once)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load&lt;/strong&gt; - save to state (Run once)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transform&lt;/strong&gt; - depending on how the component consumes state, transform the way it wants&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The change from ETL through ELT will make your code lean more and this also changes the Mindset of physician employment state: From &lt;strong&gt;thinking how to handle the event&lt;/strong&gt; to  *&lt;em&gt;**the &lt;/em&gt;&lt;em&gt;calculated output based on the current state (Computed state)&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;Applying ELT is super simple, just apply the spell.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🪄 Only save the data coming from the event to the state, and do not save anything else in the state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Original post: &lt;a href="https://thanhle.blog/blog/write-lean-state-management"&gt;https://thanhle.blog/blog/write-lean-state-management&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>redux</category>
    </item>
    <item>
      <title>Refi App - From SaaS to open source product</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Sun, 05 Dec 2021 08:18:59 +0000</pubDate>
      <link>https://dev.to/thanhlm/refi-app-from-saas-to-open-source-product-25e5</link>
      <guid>https://dev.to/thanhlm/refi-app-from-saas-to-open-source-product-25e5</guid>
      <description>&lt;p&gt;Original post from &lt;a href="https://thanhle.blog/blog/refi-app-from-saas-to-open-source-product"&gt;https://thanhle.blog/blog/refi-app-from-saas-to-open-source-product&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why should you read this article?&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lesson learned for your next side-project&lt;/li&gt;
&lt;li&gt;Why Open source is good for starting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Refi App
&lt;/h2&gt;

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

&lt;p&gt;An open-source GUI tool to make interacting with Firestore less painful&lt;/p&gt;

&lt;p&gt;&lt;a href="https://refiapp.io/"&gt;Refi App&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ...once upon the time
&lt;/h2&gt;

&lt;p&gt;When I work with Firestore for the first time, so many things excited me. It has real-time data, nicely SDK for most languages I can think of.&lt;/p&gt;

&lt;p&gt;But when really dig in, I make an accident that drops a collection by thinking it is just a document, the same issue happened to my colleagues, luckily, it is a dev environment, I just need to ask for sample data and insert those again.&lt;/p&gt;

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

&lt;p&gt;When I first worked with FireStore I faced many issues&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How can I filter documents by some criteria?&lt;/li&gt;
&lt;li&gt;How can I insert a new document from a JSON, in fact, I have to write a script to insert some new documents&lt;/li&gt;
&lt;li&gt;I have to use GC Storage to back up the data, which I need to spend more time learning about. WTF 🤬 why not just export and import by a JSON file?&lt;/li&gt;
&lt;li&gt;If I edit the same field of many documents, I need to go through documents and documents to edit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I talk to myself&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I need to save other developers from Firestore 😎&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  It might be a SaaS product
&lt;/h3&gt;

&lt;p&gt;From the beginning, I believe there are many many developers out there who have the same pain with Firestore (Yeah, there is no number or feedback to prove it, just my feeling 🤡). For that reason, I draw a beautiful canvas to prove I'm right and Refi will bring me money by solving other developers pain&lt;/p&gt;

&lt;p&gt;I built Refi App with a goal in mind&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It must be FAST and FRIENDLY for development&lt;/li&gt;
&lt;li&gt;Users shouldn't worry about their data getting stolen&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;After about 2 months of building, It was ready to launch, this is the most interesting time I have&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a new landing website&lt;/li&gt;
&lt;li&gt;Starting to marketing Refi App&lt;/li&gt;
&lt;li&gt;Thinking about domain&lt;/li&gt;
&lt;li&gt;Setting up auto-update&lt;/li&gt;
&lt;li&gt;Refi App logo&lt;/li&gt;
&lt;li&gt;Adding feedback function&lt;/li&gt;
&lt;li&gt;...etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those tasks keep going more and more and I was lost in it. It's quite difficult for me though when trying to do something I'm not good at. I want the landing page should be a professional, exciting feature introduction, but I can not design it LOL. I want to add a testimonial but I don't have any, also I don't want to fake it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting users is HARD
&lt;/h3&gt;

&lt;p&gt;The plan is, I will test it with my college, but they are afraid of using it, since their project is important and it's in the finance domain, so security is the first priority.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gfycat.com/samefamousamazontreeboa"&gt;https://gfycat.com/samefamousamazontreeboa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I tried to post it on Reddit, Twitter, and Hackernews. I didn't want to post it to Product Hunt because only want to post it there when Refi App got market-fit state, if it gets market-fit state, posting on Product Hunt will bring me a huge amount of users and upvote&lt;/p&gt;

&lt;p&gt;However... nothing follows the plan, I don't have many users and if I do, I don't know if they like it or not, I don't know if Refi app really helps or they just tried and then come back to Firestore webpage.&lt;/p&gt;

&lt;p&gt;I fail on this step many many times before and these are exactly the same steps how I fail before 🙃&lt;/p&gt;

&lt;h3&gt;
  
  
  Test and sell before building
&lt;/h3&gt;

&lt;p&gt;That is what I haven't learned. I did try to search why I can not get any users, all the way lead me to an answer&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I do not have any connection with my target users&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://gfycat.com/ifr/SandyImpureAsiantrumpetfish"&gt;https://gfycat.com/ifr/SandyImpureAsiantrumpetfish&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't know many users using Firestore. I'm not sure that my colleague has the same problem as I was when using Firestore. People using Firebase don't know me!&lt;/p&gt;

&lt;p&gt;After realizing the point I fail, I start building my Twitter profile, and this time, I don't know how to write content. I don't know how to make my tweet interesting for others.&lt;/p&gt;

&lt;p&gt;So I searching for an answer&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I was trying to post my product on social and think people will care and used it.&lt;br&gt;
Instead, giving before asking them to do anything is the key&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that time, it was totally different, I tested to share knowledge with a group at Facebook and now it got more than 1k likes (average likes on my post is about 20) which is a big change&lt;/p&gt;

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

&lt;h3&gt;
  
  
  It was getting better, but I didn't care about it like before
&lt;/h3&gt;

&lt;p&gt;Refi app is getting more users, but slowly, really slow. And I have a new job that doesn't touch anything with Firestore so I starting to ignore building Refi App.&lt;/p&gt;

&lt;p&gt;To be honest, I feel excited when building a new product, imaging it got huge users and money will flow. And when the reality is different from my expectations, I feel down. I don't have any connection with users to give me feedback and most importantly, courage me to keep building!&lt;/p&gt;

&lt;p&gt;Then I post Refi app on &lt;a href="https://tinyacquisitions.com/"&gt;https://tinyacquisitions.com/&lt;/a&gt; with the hope that someone gonna find it useful then take it off&lt;/p&gt;

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

&lt;p&gt;And it actually get someone excited, I was happy to hear that. However, they like to put a paywall to the Product, which gets me bored.&lt;/p&gt;

&lt;p&gt;When I built Refi app, I want it to have the same business as &lt;a href="https://tableplus.com/"&gt;https://tableplus.com/&lt;/a&gt; which is free for daily tasks and only charges when they want more advantage features. So I declined&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open-source?
&lt;/h2&gt;

&lt;p&gt;For now, I see many products that appear to solve the same problem I was tried with Refi app&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.rowy.io/"&gt;https://www.rowy.io/&lt;/a&gt; - turn your Firestore into Airtable&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://firefoo.app/"&gt;https://firefoo.app/&lt;/a&gt; - which is a really good tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I am no longer working with Firebase so I think it is better to make Refi lead by the community, it will open more opportunities for anyone to contribute and keep Refi moving forward&lt;/p&gt;

&lt;p&gt;It turns into a great journey&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UzDGzheV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/FFhyI6tVUAAk5rq.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--_wO_VTyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1330356033835810816/h70UIA6p_normal.jpg" alt="Thanh Le 😎 profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Thanh Le 😎
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @cuthanh15
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I have my first launch with Refi App yesterday. And here is the result 👇 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      14:25 PM - 01 Dec 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1466050821712273410" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1466050821712273410" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1466050821712273410" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Finding users is hard if you don't own any community target the issue&lt;/li&gt;
&lt;li&gt;By turning a failed SaaS into open source, you can get a community and lots more opportunities&lt;/li&gt;
&lt;li&gt;Keep #BUIDL&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>firebase</category>
      <category>product</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Build realtime dashboard using Decentralized platform - Streamr</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Mon, 29 Nov 2021 12:46:26 +0000</pubDate>
      <link>https://dev.to/thanhlm/build-realtime-dasboard-using-decentralized-platform-streamr-5djo</link>
      <guid>https://dev.to/thanhlm/build-realtime-dasboard-using-decentralized-platform-streamr-5djo</guid>
      <description>&lt;p&gt;Original post from &lt;a href="https://thanhle.blog/blog/build-realtime-dashboard-using-centralized-platform-streamr"&gt;https://thanhle.blog/blog/build-realtime-dashboard-using-centralized-platform-streamr&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why should you read this article?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A use-case of &lt;a href="https://streamr.network/"&gt;Streamr&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flow from (ELT) - extract, load, transform and visualize it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Though on real-time BI and decentralize&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://streamr-dex-chart.vercel.app/"&gt;https://streamr-dex-chart.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Story
&lt;/h3&gt;

&lt;p&gt;Our team is working mainly on data and how to gain insight via data, when doing Cryptocurrency research, I found some problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There are lots of data our there, but it takes time to gather data private data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is some BI tool out there but it depends on which data they provided (&lt;a href="https://glassnode.com/"&gt;Glassnode&lt;/a&gt;, &lt;a href="https://dune.xyz/"&gt;dune.xyz&lt;/a&gt;, &lt;a href="https://messari.io/"&gt;Messari&lt;/a&gt;, &lt;a href="https://www.intotheblock.com/"&gt;IntoTheBlock&lt;/a&gt;,...)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's not supported in real-time. I believed that in cryptocurrency or many other industries. If we can go a step ahead, we can take lots of benefits&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can say that, if we need to quick result on the result, we can use &lt;a href="https://glassnode.com/"&gt;Glassnode&lt;/a&gt; or &lt;a href="http://dune.xyz/"&gt;Dune.xyz&lt;/a&gt; but our team wants to build a tool that everyone can get what data they want, without any or basic technical knowledge and the dashboard must be in REAL-TIME.&lt;/p&gt;

&lt;p&gt;Then we come up with the expected data flow&lt;/p&gt;

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

&lt;p&gt;But this is a very starting point so we don't want to build anything from scratch, so we are going to build a really simple flow&lt;/p&gt;

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

&lt;h4&gt;
  
  
  FAQ
&lt;/h4&gt;

&lt;p&gt;What is Prefect? Why is it needed here?&lt;a href="https://www.prefect.io/"&gt;https://www.prefect.io/&lt;/a&gt; - The easiest way to build, run, and monitor data pipelines at scale.&lt;/p&gt;

&lt;p&gt;After trying many ETL tools, we think that Prefect is a perfect fit, it clean, easy to write, and the community is really good, and we can also scale the infrastructure easily (They are building a serverless Agent in future)&lt;/p&gt;

&lt;p&gt;Why not send data directly to Streamr?&lt;br&gt;
I want to but Streamr hasn't supported Python SDK for now and we don't have much time to build an SDK on Python. But I think python client is really important since most of the data tools are written in Python&lt;/p&gt;

&lt;p&gt;What is Airbyte? Why is it needed here?&lt;br&gt;
Another open-source data ingestion tool, it is the fastest-growing data ingestion tool with supported many data source and destination&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S47ZR52E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jks313wc7c213yabay26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S47ZR52E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jks313wc7c213yabay26.png" alt="Image description" width="880" height="367"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  We got funds by Streamr to #BUIDL
&lt;/h4&gt;

&lt;p&gt;As you can see, if Streamr can connect to Airbyte, it opens a huge amount of data that can flow into it platform, from Google Analysis, HubSpot, Salesforce to MySQL, BigQuery, Postgres,...&lt;/p&gt;

&lt;p&gt;With the Airbyte connectors, now you can publish tons of data into Streamr without any efforts&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/devmate-cloud/streamr-airbyte-connectors"&gt;https://github.com/devmate-cloud/streamr-airbyte-connectors&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Which support from Streamr data-fund, our team can focus on building the hardest part on the pipeline and this integration also brings them the potential to acquire more users. This is a win-win relationship!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You guys can apply data-fund to building awesome things with Streamr at &lt;a href="https://streamr.network/fund/"&gt;https://streamr.network/fund/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which sponsor for the hardest part, we now can start building&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Crawler to crawl DEX volume on &lt;a href="https://coinmarketcap.com/rankings/exchanges/dex/"&gt;https://coinmarketcap.com/rankings/exchanges/dex/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building a frontend app to get real-time data and visualize it&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/devmate-cloud/streamr-dex-chart"&gt;https://github.com/devmate-cloud/streamr-dex-chart&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/thanhlmm/prefect_cmc"&gt;https://github.com/thanhlmm/prefect_cmc&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  ...on building real-time BI tool
&lt;/h3&gt;

&lt;p&gt;This is a really hard journey but we started with a very first step, there are lots of problems we need to solve&lt;/p&gt;
&lt;h4&gt;
  
  
  Building a Crawling tool for anyone is hard
&lt;/h4&gt;

&lt;p&gt;The internet is an open world that we can get many data there, but doing that with scale is hard. Most of the data is their website assets, so you end up building a crawling tool to get that data or buy from them via API. That why their business is, to make it hard to be crawl&lt;/p&gt;

&lt;p&gt;Our team is thinking of building a SQL-like language to crawl data&lt;/p&gt;

&lt;p&gt;The idea is that we can crawl most of the website data via SQL syntax&lt;/p&gt;

&lt;p&gt;Eg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"https://coinmarketcap.coin"&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;"cmc-link"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"https://streamr.network"&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="n"&gt;CHILD&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="nv"&gt;".Hero__Inner"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Realtime BI tool
&lt;/h4&gt;

&lt;p&gt;Its lack of a tool to visualize real-time data, most of them can do batch data by querying from data-warehouse database but supported in real-time is a hard problem.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dmr0WmqG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/FEkSG6LaQAAsd5n.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--_wO_VTyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1330356033835810816/h70UIA6p_normal.jpg" alt="Thanh Le 😎 profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Thanh Le 😎
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @cuthanh15
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      If you plan to build real-time pipeline, you MUST use &lt;a href="https://twitter.com/apachekafka"&gt;@apachekafka&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:35 PM - 19 Nov 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1461719755555946500" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1461719755555946500" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1461719755555946500" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Kafka is the only tool that we can use to build a real-time data pipeline, and we only see &lt;a href="https://metatron.app/"&gt;https://metatron.app/&lt;/a&gt; supported Kafka right now&lt;/p&gt;

&lt;h4&gt;
  
  
  Is Streamr fit?
&lt;/h4&gt;

&lt;p&gt;No, at the moment. By far, Streamr is supported most of the basic cases: We can subscribe to real-time data, get past data by time,... but it doesn't support the most important cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Process the data. Imagine you have a stream input of DEX volume data by every 30 mins and we need a stream of DEX volume data by every 4 hours as output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And we think Streamr can utilize its nodes to run lots of potential use-cases not just as an infrastructure to stream data. For eg:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Support smart contract so we can make a node as a crawler data point. By doing so, we can leverage lots of nodes on Streamr Network to get data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support smart contract so it can process stream like my above example. We got and stream as input → Smart contract → stream as output&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our team don't want to expose my Private key when integrating Streamr on the frontend, we can hide it by running the Streamr node on my server but we think it takes effort to do and operate our node&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is lots of works to do but our team believed, which the fast-growing industry, we can have those abilities in the near future&lt;/p&gt;

</description>
      <category>blockchain</category>
    </item>
    <item>
      <title>Guide to choosing state management library for your next project</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Wed, 10 Nov 2021 05:13:32 +0000</pubDate>
      <link>https://dev.to/thanhlm/guide-to-choosing-state-management-library-for-your-next-project-13mi</link>
      <guid>https://dev.to/thanhlm/guide-to-choosing-state-management-library-for-your-next-project-13mi</guid>
      <description>&lt;p&gt;Read the original post from &lt;a href="https://thanhle.blog/blog/guide-to-choosing-state-management-library-for-your-next-project" rel="noopener noreferrer"&gt;https://thanhle.blog/blog/guide-to-choosing-state-management-library-for-your-next-project&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you read this article?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There is a set of criteria when choosing a library for Frontend State Management&lt;/li&gt;
&lt;li&gt;What is state management?&lt;/li&gt;
&lt;li&gt;What does state management care about?&lt;/li&gt;
&lt;li&gt;Have a bunch of reasons to drop Redux&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usually, people who find this post gonna be in one of two groups&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Frontend engineer is too tired, suffer from &lt;code&gt;redux&lt;/code&gt; 😵‍💫&lt;/li&gt;
&lt;li&gt;Are you just starting out in frontend and want to learn more about state management&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're in group 1 then... Great, I'm writing this post with 80% of my energy wanting to get rid of &lt;code&gt;redux&lt;/code&gt; 😄. If you belong to group 2, this post will help you have more perspectives on state management, how to act cool with colleagues&lt;/p&gt;

&lt;h2&gt;
  
  
  So what the hell is State management?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521389740%2FLZ557YSSz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521389740%2FLZ557YSSz.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find "what is state management" on Google, there are quite a few definitions, but it can be summarized into two main ideas as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;☠️ State is the skeleton of the application&lt;/li&gt;
&lt;li&gt;🏃 State management is to manage that skeleton&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's fuking simple, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  So which state management to choose?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;⚛️ In this part, I only focus on React, because my current job is focusing on React.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short&lt;/strong&gt;: Basically you don't need any state-management library, React + ReactContext + API query library is enough 🤷‍♂️&lt;/p&gt;

&lt;p&gt;%[&lt;a href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367" rel="noopener noreferrer"&gt;https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367&lt;/a&gt;]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;People often choose Redux before they need it. “What if our app doesn’t scale without it?” Later, developers frown at the indirection Redux introduced to their code. “Why do I have to touch three files to get a simple feature working?” Why indeed!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Basically, most of your state is only shared in one feature, so it will be encapsulated in a route (eg: &lt;code&gt;/users&lt;/code&gt;, &lt;code&gt;/posts&lt;/code&gt;). Therefore, for each route, we only need one &lt;code&gt;ReactContext&lt;/code&gt; to handle 80% of cases.&lt;/p&gt;

&lt;p&gt;Some features will need data users, if so, do we have to query users every time? Most modern query libraries solve this case for you by caching. Try &lt;a href="https://swr.vercel.app/" rel="noopener noreferrer"&gt;swr&lt;/a&gt; or &lt;a href="https://react-query.tanstack.com/" rel="noopener noreferrer"&gt;react-query&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If things start to get complicated, add libraries like &lt;a href="https://recoiljs.org/" rel="noopener noreferrer"&gt;Recoiljs&lt;/a&gt;, &lt;a href="https://jotai.org/" rel="noopener noreferrer"&gt;Jotai&lt;/a&gt;. These libraries can be added and easily replaced &lt;code&gt;useState&lt;/code&gt; by Search &amp;amp; Replace.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't complicate things when it's simple, prepare for it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Long&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521654983%2FhAtqGWgnR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521654983%2FhAtqGWgnR.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;State also has many different types, so there are also many different types of classification, but I found this article is really good at state classification.&lt;/p&gt;

&lt;p&gt;%[&lt;a href="https://javascript.plainenglish.io/do-you-know-the-5-types-of-states-in-react-8734a04a5ffb" rel="noopener noreferrer"&gt;https://javascript.plainenglish.io/do-you-know-the-5-types-of-states-in-react-8734a04a5ffb&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Some best practices&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Form state&lt;/strong&gt;: Do not move it to the global state/store .... whatever. Hey, it's best in just one component. So it &lt;code&gt;react-hook-form&lt;/code&gt; is enough.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Navigation state&lt;/strong&gt;: &lt;code&gt;react-router&lt;/code&gt; is almost the default in every project, better we ignore it. If you want to integrate with the global state, the best sync direction is Navigation state → Global state. This case is often seen when making a search page with a filter&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok we have 3 guys left&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Logical state&lt;/li&gt;
&lt;li&gt;Server state&lt;/li&gt;
&lt;li&gt;Browser state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 &lt;em&gt;**That means we need to find a state management library to manage&lt;/em&gt;* the Logical state, Server state, and Browser state*&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy to add
&lt;/h3&gt;

&lt;p&gt;A good library, for me, DX must be good, I don't want to spend half a day just trying to figure out how to integrate it into my app.&lt;/p&gt;

&lt;p&gt;Since state management, in particular, is a complicated thing, so of course, it's complicated to add, but don't make it any more complicated... Redux 😡&lt;/p&gt;

&lt;p&gt;&lt;em&gt;However, this part only needs to be done a few times when coding a new project, so this criterion is only slightly important.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy to write, easy to understand
&lt;/h3&gt;

&lt;p&gt;Don't force yourself to code a normal use case: &lt;code&gt;Query API → Render list user&lt;/code&gt; in the following step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dispatch query action with &lt;code&gt;keyword&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write a reducer that takes a query, then dispatches a saga action&lt;/li&gt;
&lt;li&gt;Write action sagas&lt;/li&gt;
&lt;li&gt;Write 2 more reducers for sagas succeed case and fail case&lt;/li&gt;
&lt;li&gt;If successful, merge the received data into the state tree&lt;/li&gt;
&lt;li&gt;Mapping state into UI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the job that I find the most de-optimized that most frontend engineers have to do. It's true that "people make it complicated", a good library is a library that must help devs and "enjoy the moment".&lt;/p&gt;

&lt;p&gt;In addition, I don't have to spend all day explaining to a Junior that the data will go through these steps, and he replied "it's too confusing 😭", and then I can't hide when it doesn't work.&lt;/p&gt;

&lt;p&gt;💡&lt;em&gt;So easy to write also means easy to understand&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Community = Easy to debug/enhance
&lt;/h3&gt;

&lt;p&gt;Community is not natural but is always a criterion that everyone cares about when choosing Library, Framework, ....etc&lt;/p&gt;

&lt;p&gt;Community is the part that can cover lots of factors.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow the doc not add lib → search google → done.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Can't write → search google → done.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So the power of a library comes from the community that supports it, and Redux is on-top in this criteria&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Often core libraries like this can't, or are very difficult to replace when you realize: "this library is running slow, I can't optimize"&lt;/p&gt;

&lt;p&gt;Therefore, Performance is a criterion to consider when this is a long-term project and has a huge future expansion.&lt;/p&gt;

&lt;p&gt;Performance can be divided into 2 criteria:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Load time&lt;/strong&gt; - often depends on library size, network,...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive time&lt;/strong&gt; - usually depends on the "intrinsic" of that library&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The state management focuses mainly on data logic, so the part &lt;code&gt;Interactive time&lt;/code&gt; is the most important. Especially in react context, you need to pay attention to how it triggers re-render component when the state is updated&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521831791%2FDRxFUlumy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521831791%2FDRxFUlumy.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;If your project has a small to medium scope, you should not care about this&lt;/strong&gt;. I think the scope of this type of project should be concerned with the code so that it is fast and easy to understand. Optimized but only 10ms faster is not worth the trade-off. I had to fix a lot of small and unpredictable bugs because the previous coder focused on optimizing too early!&lt;/p&gt;

&lt;h4&gt;
  
  
  What type of project is it suitable for?
&lt;/h4&gt;

&lt;p&gt;It is not natural that there are so many state-management libraries, simply for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They are tired of Redux 😫&lt;/li&gt;
&lt;li&gt;Depending on the project with different complexity, there will be suitable tradeoffs → create a library suitable for that tradeoff&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;👉 &lt;strong&gt;This is the most important criterion&lt;/strong&gt; that I see the difference between a "technology enthusiast" and a "pragmatic technology enthusiast". I met some people who really liked new technology, this new one was so cool but he accidentally forgot, that cool thing is never applied in the project, sometimes it's also an anchor for the team to move forward 🙃&lt;/p&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;This is the result of my assessment after working on a real project with some of the top libraries in this field, but this is just a personal perspective, do your own research.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636522206952%2FI7PM5_VFV.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636522206952%2FI7PM5_VFV.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚫 &lt;strong&gt;Please! Don't use Redux anymore&lt;/strong&gt; - Redux only handles well Logical state&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to add server state, add redux-saga, or redux-thunk go! - - At the same time, spend an extra day reading the document to see what they are.&lt;/li&gt;
&lt;li&gt;1 day to put them together, and 1 week to debug why not run 🙂&lt;/li&gt;
&lt;li&gt;Sticking to react? The extra redux-react&lt;/li&gt;
&lt;li&gt;App after a while of coding, it runs slow? Append &lt;code&gt;reselect&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is too much to read, too much to code and learn to manage the state. In fact, redux is the most de-optimize factor in the frontend stack&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521901873%2Flnw2KeEWt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1636521901873%2Flnw2KeEWt.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hopefully, through this post, you will have an overview of state management and how it is used in react. And especially, please, don't use redux if it doesn't fit anymore&lt;/em&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
    </item>
    <item>
      <title>Morphling - dApp to join Binance Launchpad without any restriction</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Tue, 02 Nov 2021 12:57:53 +0000</pubDate>
      <link>https://dev.to/thanhlm/morphling-dapp-to-join-binance-launchpad-without-any-restriction-3ihp</link>
      <guid>https://dev.to/thanhlm/morphling-dapp-to-join-binance-launchpad-without-any-restriction-3ihp</guid>
      <description>&lt;p&gt;📝 Morphling - dApp to join Binance Launchpad without any restriction&lt;br&gt;
thanhle.blog (1377 words)&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#8fab4e693a3f487bba9f9916fbaa0db6"&gt;&lt;/a&gt;Why should you read this article?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;More perspective on dAPP. Why do I use Smart Contract instead of something centralized?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tips when building apps on EVM-chain (Etherium, Binance Smart Chain, ...)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The reason this dApp failed (If it fails in the future ‍♂️)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#3dccfa5218f7464794155f2f52ceeb98"&gt;&lt;/a&gt;What app is that?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://morphling.vercel.app/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x9Apa81c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fc4e171a4-e63e-48ee-b984-0a5d70d98571%252FFCwz2cYUYAIpmus.jpeg%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D3188031b73850919be7b254538db018e2baf28a2225d862aa88ac1f1b21796fc%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D04d0a1a1-1446-4667-8d7a-55f55b7fed90%26cache%3Dv2" alt="https://morphling.vercel.app/" width="" height=""&gt;&lt;/a&gt;Morphling is a dApp that allows people in crypto-banned countries to join Binance Launchpad, specifically China.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#e446f5b110b94c3f802b5e87e5d5dcd1"&gt;&lt;/a&gt;Why build this?
&lt;/h3&gt;

&lt;p&gt;If any of you are used to sending money to CZ or Binance, you must be familiar with a Feature on Binance: &lt;a href="https://coin98.net/binance-launchpad"&gt;Launchpad&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With recent data, most of these Launchpad rounds bring huge profits to investors and are almost risk-free, as long as you hold BNB, you got money 🤑&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I91I2YB0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F65965add-babc-4075-bcfa-c7d066a8f07b%252Fphoto_2021-10-30_13.25.28.jpeg%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D5e6f14c6c3002b87219f56157171013c69eac74cc7cefa61ed7e3153c36f3904%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D69b1fe46-63b7-483f-a809-93a38593d3ce%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I91I2YB0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F65965add-babc-4075-bcfa-c7d066a8f07b%252Fphoto_2021-10-30_13.25.28.jpeg%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D5e6f14c6c3002b87219f56157171013c69eac74cc7cefa61ed7e3153c36f3904%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D69b1fe46-63b7-483f-a809-93a38593d3ce%26cache%3Dv2" alt="notion image" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, there is one problem: Binance does not allow users in some countries to join Launchpad, typically China.&lt;/p&gt;

&lt;p&gt;Users from the following countries or regions will not be able to participate in token sales on the Binance Launchpad platform:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Belarus, People's Republic of China, Democratic Republic of Congo, Cuba, Iraq, Iran, North Korea, Sudan, Syria, United States of America and its territories (American Samoa, Guam, the Northern Mariana Islands, Puerto Rico, and the U.S. Virgin Islands), Zimbabwe.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To get around this limitation, some of my Chinese colleagues have sent me BNB to join the Launchpad. It was time to hold the BNB number with a value of more than $100,000, in my mind, those questions popped up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What if I lose this BNB number?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What if I "accidentally" lose it? Can the guys in China catch me? Or do I do a few things to build trust and then wait for more than 10 million and then "accidentally" lose it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After getting the token from Binance, how can I share it with everyone?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I joined Launchpad to help the other guys, I also encountered some pretty annoying things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I need to calculate the share ratio for each one, it's quite boring, sometimes I have a few BNB put in, then the calculation is messed up again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While holding Launchpad, someone withdraws BNB because the loan interest is increasing dramatically 🏃‍♂️, or sometimes while holding, someone deposits extra BNB to participate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Distribute the reward for each person. This part is the most annoying to me because it takes lots of time. After calculating the number of BNB and Token to distribute to each person, I must: &lt;code&gt;Ask for their Address, confirm, go to Binance to withdraw, input OTP email, input OTP password, input OTP 2FA, input my YubiKey, confirm that they have received Token&lt;/code&gt; 😫. And each user I will have to redo this series twice because Binance does not support sending BNB and Token at the same time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There was a time when I sent the wrong Token via BNB, so I had to send all the tokens to him and ask him to re-distribute the token to others. And my friend also had to do endless steps like me to re-distribute it.&lt;/p&gt;

&lt;p&gt;If we look broadly, it can be seen that this model only works based on individual beliefs with each other. That party trust me, so they send lots of BNB to me, I also really trust them once I sent all the rewards to that person.&lt;/p&gt;

&lt;p&gt;So I came up with &lt;code&gt;Morphling&lt;/code&gt;It's a Dota hero famous for his ability to change between Agility and Strength (Damage and HP)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jSdH-oRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F0811195f-a4b2-475d-afed-e7f5b4f67c96%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253Da6538970eee57f9ec754419e9bd2d10986adb9fe3bbe5a93e24ff86f21bfec93%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D899801c7-17ec-48de-a684-5425268e9488%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jSdH-oRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F0811195f-a4b2-475d-afed-e7f5b4f67c96%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253Da6538970eee57f9ec754419e9bd2d10986adb9fe3bbe5a93e24ff86f21bfec93%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D899801c7-17ec-48de-a684-5425268e9488%26cache%3Dv2" alt="notion image" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v8i8gVR4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F40e5abda-c91e-4eb3-ba3b-8b7f289a9f28%252FBinance_Launchpad_investment_%2525281%252529.jpg%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D1e9547ba290a7f2ed5e722960a91095ddb7e7ef5def896b182e5c50c97d1939c%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3De1db32e2-1e5c-45c8-b0a8-1a7579fc8864%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v8i8gVR4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F40e5abda-c91e-4eb3-ba3b-8b7f289a9f28%252FBinance_Launchpad_investment_%2525281%252529.jpg%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D1e9547ba290a7f2ed5e722960a91095ddb7e7ef5def896b182e5c50c97d1939c%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3De1db32e2-1e5c-45c8-b0a8-1a7579fc8864%26cache%3Dv2" alt="notion image" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#71ac5430609e4ce1a05b2ed6d2352d57"&gt;&lt;/a&gt;Operation model
&lt;/h4&gt;

&lt;p&gt;My idea is quite simple, the system will have 3 pools&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cover pool&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Staking pool&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reward pool&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To solve the trust issue when I am the representative holding BNB, I will need to put some money in to make a trust. When things go wrong, this pool cover will be un-locked to distribute among those who have put BNB into staking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After it's time to hold BNB on Launchpad, I will lock the staking pool and withdraw funds from this pool, then put it on Binance to join the launchpad.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, when Binance gave me back my BNB and Token. I just need to withdraw and put it into the pool. Then this pool will be divided equally according to the rate deposited in the staking pool&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By circulating BNB and tokens in the 3 pools above, I don't have to run the calculation, distribute tokens to everyone manually (Save me 10 minutes for each user, and reduce the risk of wrong input number, or sent by mistake at the same time). In addition, the timing of returning tokens to everyone is also quite sensitive, price can go up and down!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#568cc0ea67fb42d6bb6bc1ad1ec32b99"&gt;&lt;/a&gt;Income &lt;strong&gt;🤑&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Nothing for free, I charge 5% for the reward token. So if I do it manually, holding about $10,000 will only get paid about $50-$100, the risk ratio is too high. Therefore, if I can scale this model, I can have a decent cash flow without doing much&lt;/p&gt;

&lt;p&gt;Ex: 100 users, each deposit 5BNB and get about $100 token reward each person&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So I can make a profit: 100*100*5% = $500&lt;/strong&gt; already (Depending on the Pump level of the reward token, the profit may be different)&lt;/p&gt;

&lt;p&gt;My part of the risk will be pushed to the Smart Contract side, or I will not suffer anything, or I will lose everything&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#e6f6333740414da5b65f1646a226b74e"&gt;&lt;/a&gt;It's not that easy &lt;strong&gt;😌&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In terms of operation, it is quite simple, but if you think more deeply, you will need to handle a lot of questions?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the cover is too little, will the user trust to stake BNB?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What if the amount of cover is greater than the amount of BNB in the staking pool? Then just put 1BNB and then claim to redeem 1.2BNB cover is done, it's a risk-free investment in a few minutes 🤷‍♂️.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If after getting the token, BNB from Launchpad, if I eat a little less and then deposit it into the Reward pool, how will the Users side handle it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What's the use of this dApp when buying a Binance account in another country?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Usually, the token payment time will be delayed randomly compared to the time that the token is listed on the exchange, if that token dumps or pumps, how does it affect this model?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each user participating in Launchpad will be limited to the maximum number of tokens that can be purchased, called Hardcap, so if I need to to run this modal to many other Binance accounts, I need to design the modal so that they will not take BNB and run away.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#74fdf659cfd140bb852c175a6b5bb663"&gt;&lt;/a&gt;Why Smart Contracts?
&lt;/h3&gt;

&lt;p&gt;Naming a piece of code that runs on ETH or Binance is already something that I find very cool! Why not set it to Decentralize Logic, Distributed code,...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y_URxiGt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Ff65f6ef0-172b-49fb-b69b-7129347216a3%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D2ccaa5443543f7d4475d5962ab197a48a5da4eb0f66102fda829a7f4bc12135a%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D5fc081ff-8894-456f-92e3-4ec860627833%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y_URxiGt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Ff65f6ef0-172b-49fb-b69b-7129347216a3%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D2ccaa5443543f7d4475d5962ab197a48a5da4eb0f66102fda829a7f4bc12135a%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D5fc081ff-8894-456f-92e3-4ec860627833%26cache%3Dv2" alt="notion image" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By definition, a contract is an agreement between 3 parties: Party A, Party B, and a third party to ensure fairness between Party A and Party B. In fact, all contracts that you agree to. For daily transactions such as labor contracts, real estate purchase and sale contracts, etc., the third party is the state.&lt;/p&gt;

&lt;p&gt;The smart contract is 3rd party to ensure the cooperation of party A and party B is the logical lines that you code. Therefore, in terms, the economic model in Smart Contract must be very careful and carefully calculated. It's like you're coding a strict referee in a football match.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--744TtmPo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F2cf05794-3af6-473f-b52e-53bd167cfc48%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D5115f02de0a474684f55e9606c2aaecdd9fbbec47a78a1828a0020708a7bfb13%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D16f0a787-9f9b-43e3-8bea-b9d6dbf03e63%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--744TtmPo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F2cf05794-3af6-473f-b52e-53bd167cfc48%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D5115f02de0a474684f55e9606c2aaecdd9fbbec47a78a1828a0020708a7bfb13%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D16f0a787-9f9b-43e3-8bea-b9d6dbf03e63%26cache%3Dv2" alt="Pierluigi Collina" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pierluigi Collina &lt;/p&gt;

&lt;p&gt;As you can see, in &lt;code&gt;Morphling&lt;/code&gt;, there is party A: BNB recipient to join Launchpad, party B: stake BNB to profit from participating in Launchpad. And the third party, which is a smart contract that is responsible for ensuring that Party A does not cheat on Party B, and Party B does not cheat on Party A or if even they cheat, then, in the end, the cheater will also be the one pay the bill 😭&lt;/p&gt;

&lt;p&gt;Therefore, designing a set of rules for this Smart Contract guy needs a lot of brain 🧠 power and it is the most basic foundation in the era of Decentralized everything. Does your platform have developers? Are there any users using it? Is anyone participating in running the node? Is there any user deposit liquidity pool?... All must be built on the set of rules it defines.&lt;/p&gt;

&lt;p&gt;This is a very difficult and interesting problem, maybe I will write more on this topic, but basically, the Rules will be built on 2 basic fundamentals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Game theory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nash equilibrium&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l8REjn1k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Ffd61b8c4-b6cc-49e8-b50d-13d02df94c7b%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D52dd3ad332511aaf71ea2bef22377e9b92850d130e2c8d4c153a20ed8238421c%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D461464ed-e153-477f-a57e-631a64c5e671%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l8REjn1k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.notion.so/image/https%253A%252F%252Fs3.us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Ffd61b8c4-b6cc-49e8-b50d-13d02df94c7b%252FUntitled.png%253FX-Amz-Algorithm%253DAWS4-HMAC-SHA256%2526X-Amz-Credential%253DAKIAT73L2G45O3KS52Y5%25252F20211102%25252Fus-west-2%25252Fs3%25252Faws4_request%2526X-Amz-Date%253D20211102T100252Z%2526X-Amz-Expires%253D86400%2526X-Amz-Signature%253D52dd3ad332511aaf71ea2bef22377e9b92850d130e2c8d4c153a20ed8238421c%2526X-Amz-SignedHeaders%253Dhost%3Ftable%3Dblock%26id%3D461464ed-e153-477f-a57e-631a64c5e671%26cache%3Dv2" alt="notion image" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#cdc7b786c1ac4ffd8817276a53193a69"&gt;&lt;/a&gt;Where's the code?
&lt;/h4&gt;

&lt;p&gt;I'm beta testing this app, so I won't publicize the code at the moment, but will soon. Stay tuned!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://thanhle.blog/blog/1#310a3ad902fd41bcaaff135cce7ada7c"&gt;&lt;/a&gt;Building journey
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;I'm thinking of a way to show some problems/tips during app build like a timeline. But right now, it's not built yet, so I leave this section blank&lt;/em&gt;&lt;/p&gt;

</description>
      <category>product</category>
    </item>
    <item>
      <title>Electron multiple Tabs without dealing with performance</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Wed, 28 Apr 2021 06:36:56 +0000</pubDate>
      <link>https://dev.to/thanhlm/electron-multiple-tabs-without-dealing-with-performance-2cma</link>
      <guid>https://dev.to/thanhlm/electron-multiple-tabs-without-dealing-with-performance-2cma</guid>
      <description>&lt;p&gt;Hi everyone,&lt;/p&gt;

&lt;p&gt;I'm Thanh, Refi App creator&lt;/p&gt;

&lt;p&gt;In the journey of building a tool to interact with Firestore, I found an insight that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers usually working on multiple projects at the same time&lt;/li&gt;
&lt;li&gt;And they also tend to use multiple tabs on the browser to work with the same Firebase project to have multiple views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indeed, Refi App should support them by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement user's familiar UX tabs - Like what chrome does&lt;/li&gt;
&lt;li&gt;Hotkeys all the thing (&lt;code&gt;Cmd + T&lt;/code&gt; for new tab, &lt;code&gt;Cmd + W&lt;/code&gt; to close current one)&lt;/li&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  In search of solutions
&lt;/h2&gt;

&lt;p&gt;It popped out on my head for some solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just use some Tabs component, there are hundred of Tabs components out there&lt;/li&gt;
&lt;li&gt;Is there any optimized solution for &lt;code&gt;electron&lt;/code&gt;? Here we have &lt;a href="https://github.com/brrd/electron-tabs" rel="noopener noreferrer"&gt;https://github.com/brrd/electron-tabs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But none of them can give me the right solution, why?&lt;/p&gt;

&lt;p&gt;If I use Tabs component in react, the multiple application will work on just one process and it app is will hanging when we have more than 3 tabs open since Refi App do lots of things in the background: It listens on the database changes and update the UI in realtime, showing many documents at the same time in the Table view&lt;/p&gt;

&lt;p&gt;How about &lt;code&gt;electron-tabs&lt;/code&gt;, it uses &lt;code&gt;webview&lt;/code&gt; under the hood. I tested it and end up can not make my app running properly due to application architecture. The &lt;code&gt;webview&lt;/code&gt; also have many issues remains that event Slack or Figma team can not deal with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://slack.engineering/growing-pains-migrating-slacks-desktop-app-to-browserview/" rel="noopener noreferrer"&gt;Growing Pains: Migrating Slack's Desktop App to BrowserView - Slack Engineering&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/blog/introducing-browserview-for-electron/" rel="noopener noreferrer"&gt;Introducing BrowserView for Electron&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrrnub88h50ewsnvewam.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrrnub88h50ewsnvewam.jpg" alt="Refi App architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But those awesome team has introduced a great alternative solution for it &lt;code&gt;BrowserView&lt;/code&gt;. It basically works like &lt;code&gt;BrowserWindow&lt;/code&gt; but you can put &lt;code&gt;BrowserView&lt;/code&gt; anywhere in &lt;code&gt;BrowserWindow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It likes position relative/absolute in CSS, the &lt;code&gt;BrowserWindow&lt;/code&gt; is the parent which has &lt;code&gt;position: relative;&lt;/code&gt; and the &lt;code&gt;BrowserView&lt;/code&gt; is children have &lt;code&gt;position: absolute;&lt;/code&gt;. And yes, you can put many BrowserView inside its parent as you want, just like CSS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7v0s6xozkh7kshcr23a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7v0s6xozkh7kshcr23a.png" alt="BrowserWindow = position relative, BrowserView = position Absolute"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BrowserWindow = position relative, BrowserView = position Absolute&lt;/p&gt;

&lt;h2&gt;
  
  
  Here is the output
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gd5pje8ftme5neg8ync.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0gd5pje8ftme5neg8ync.jpg" alt="Refi App using BrowserView"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The output is awesome, each tab instance has its own process, and the performance is incredible, it like we change tab in the Chrome browser (In fact, the mechanism is almost the same as Chrome is doing) &lt;/p&gt;




&lt;p&gt;I'm too tired right now so if you're curious about how to do that, let's wait for the next post.&lt;/p&gt;

&lt;p&gt;If you guys think this post is useful and one to know more trick on optimize the performance of Electron, let's follow me at &lt;a href="https://twitter.com/cuthanh15" rel="noopener noreferrer"&gt;https://twitter.com/cuthanh15&lt;/a&gt;&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>electron</category>
      <category>react</category>
      <category>firestore</category>
    </item>
    <item>
      <title>RecoilJS in practical - complex application</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Thu, 01 Apr 2021 16:07:19 +0000</pubDate>
      <link>https://dev.to/thanhlm/recoiljs-in-practical-complex-application-33kn</link>
      <guid>https://dev.to/thanhlm/recoiljs-in-practical-complex-application-33kn</guid>
      <description>&lt;p&gt;Hi there,&lt;br&gt;
I just use Recoil for my own product for the first time.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/thanhlm" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F605978%2F60384c72-76a2-4ce6-8e48-af8d6a520661.jpeg" alt="thanhlm"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/thanhlm/refi-app-a-tool-to-make-developer-less-painful-when-interacting-with-firestore-db-23of" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Refi App -  A tool to make developer less painful when interacting with Firestore DB&lt;/h2&gt;
      &lt;h3&gt;Thanh Minh ・ Mar 30 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#firebase&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;So I decided to share my own experience when using Recoil 🤘&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;With the non-requirement of Refi App, it must be fast to bring the best DX so I need something to manage the state in a very optimized way&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not Redux? Zustan? DVA?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The boilderplace is so fukin hard. Besides, it really hard for optimizing to only render a component which subscribe to a sub-tree state. I need to use &lt;code&gt;selector&lt;/code&gt;, &lt;code&gt;memorize&lt;/code&gt;, &lt;code&gt;immutable&lt;/code&gt;, ...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why not MobX? MST?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has been a long time since I last use Mobx, MST. It's cool, but now the world has changed a lot, no more Class component, so I don't know it supports a lot.&lt;/li&gt;
&lt;li&gt;One more thing I don't want to use MobX is that the API is changed a lot in each major version. No! I don't want to use an outdated library for the rest of my life&lt;/li&gt;
&lt;li&gt;I feel can not control how Component will render when I use MobX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Recoil?&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpzj5eam5j7w5xhjmyfm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpzj5eam5j7w5xhjmyfm.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It solves my concern, each component is subscribed to a very small state object (called atom) and only render once they changed&lt;/li&gt;
&lt;li&gt;It plays nice with Functional Component. You can easily change &lt;code&gt;useState&lt;/code&gt; to &lt;code&gt;useRecoilState&lt;/code&gt; and vice versa. It's cool because "Alway use local state, only move it to global once needed"&lt;/li&gt;
&lt;li&gt;I can map the product concept to state in my brain. A cell in a table should be an atom, so that the cell will render on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How can I struct my state?
&lt;/h2&gt;

&lt;p&gt;When using recoil, your state will build from pieces of atom - A bottom-up approach. So that if you don't have a strategy for structuring it, you will end up with tons of atom&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3oxHQfQJqCpqtoeDZK/source.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3oxHQfQJqCpqtoeDZK/source.gif" alt="Lots of atom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decided to orders those atoms by&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;firebase atoms&lt;/li&gt;
&lt;li&gt;navigator atoms&lt;/li&gt;
&lt;li&gt;UI atoms&lt;/li&gt;
&lt;li&gt;hotkeys atom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p0ylj96q71psoi8jf9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p0ylj96q71psoi8jf9f.png" alt="My atoms"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it is biz state, I divided it by domain&lt;br&gt;
If it is for something to manage display, I divided it by its function&lt;/p&gt;

&lt;p&gt;As you can see in the images, I also make a &lt;code&gt;.action.ts&lt;/code&gt; files. Once using recoil in a complex app, you will often need to update state of many atoms for one action.&lt;br&gt;
For eg: Once users click on the &lt;code&gt;Commit&lt;/code&gt; button, I will need to submit all the modified/new/deleted documents to the server, I also need to update a UI atom to show loading.&lt;/p&gt;

&lt;p&gt;By splitting all actions to &lt;code&gt;.action.ts&lt;/code&gt; file. I can list out all the use cases and convenient to not mess my mind once add or edit something.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj16ajajmxh1k45lfzzoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj16ajajmxh1k45lfzzoz.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One more thing is all the atoms, selectors must postfix with &lt;code&gt;Atom&lt;/code&gt;. If not your brain will get confused when using it. Is this object is Atom Value, Atom State, or just a local state?&lt;/p&gt;

&lt;p&gt;For that strategy, RefiApp tech about 60 atoms object so far. I'm happy with the current status but I think I gonna divide it for smaller if the app is grow&lt;/p&gt;

&lt;h1&gt;
  
  
  The funny parts
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ZqlvCTNHpqrio/source.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ZqlvCTNHpqrio/source.gif" alt="Funny parts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As I write above, it really easy to convert from &lt;code&gt;useRecoilState&lt;/code&gt; to &lt;code&gt;useState&lt;/code&gt; which is free my brain a lot. I don't need to ask myself, should I put it at global every time I try to introduce a new state.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;atom&lt;/code&gt; state can easily convert to &lt;code&gt;selector&lt;/code&gt; and vice versa. Why I will need that?
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzbv3xorj1awkkm0az2t.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the image above, I have a &lt;code&gt;propertyListAtom&lt;/code&gt; to store the &lt;code&gt;propertys&lt;/code&gt; that will show in each collection table. It will have an empty array &lt;code&gt;[]&lt;/code&gt; as the default value. But I have a case that if users access a collection for the first time, I will generate some &lt;code&gt;property&lt;/code&gt; to put on that list so that I introduce a &lt;code&gt;null&lt;/code&gt; type for that atom. If I change the type of &lt;code&gt;propertyListAtom&lt;/code&gt; then I gonna need to find everywhere using that atom to make an update.&lt;br&gt;
No, you don't need to do that!. I just add a new atom &lt;code&gt;propertyListCoreAtom&lt;/code&gt; and turn my old atom one to &lt;code&gt;selector&lt;/code&gt;. Really enjoy!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components will only render if its subscribed atoms update which is my own goal. No more energy to put on a stupid thing like &lt;code&gt;redux&lt;/code&gt; and &lt;code&gt;selector&lt;/code&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The awful parts
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/h5Y8UipmlqHCw/source.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/h5Y8UipmlqHCw/source.gif" alt="awful parts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have to write all the logic in a component, there is no official way to mutate a state from outside. I know they have reason to make it, but it feels poor for developers to follow it. But I found a way to eliminate that &lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/facebookexperimental/Recoil/issues/289" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        There is a way to update states on recoilJS outside of component?
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#289&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/orhalimi" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F6633344%3Fv%3D4" alt="orhalimi avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/orhalimi" rel="noopener noreferrer"&gt;orhalimi&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/facebookexperimental/Recoil/issues/289" rel="noopener noreferrer"&gt;&lt;time&gt;Jun 09, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;So I'm trying recoilJS for a js game that I am building and it pretty neat, but the need to update atoms from components only feels like a limitation.&lt;/p&gt;
&lt;p&gt;To create a game loop, I put all the logic on empty component so I will be able to read and write states. Even if I will construct the logic outside of the component, I will need especially move different stats around all the time. There is a way to update atoms outside of react component (not via hooks)?&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/facebookexperimental/Recoil/issues/289" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;There are some issues on performance still not solve yet. The components will render if the &lt;code&gt;selector&lt;/code&gt; value is not changed (their dependencies changed) &lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/facebookexperimental/Recoil/issues/924" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        The component rerender even the value from selector is not change
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#924&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/thanhlmm" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F9281080%3Fv%3D4" alt="thanhlmm avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/thanhlmm" rel="noopener noreferrer"&gt;thanhlmm&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/facebookexperimental/Recoil/issues/924" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 17, 2021&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;How to reproduce&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codesandbox.io/s/recoil-test-8jove?file=/src/App.js" rel="nofollow noopener noreferrer"&gt;https://codesandbox.io/s/recoil-test-8jove?file=/src/App.js&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I have an atom to keep track an array of item - &lt;code&gt;AtomA&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A selector to validate the length of above array - &lt;code&gt;SelectorB&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So every time I add new item to &lt;code&gt;AtomA&lt;/code&gt; but the &lt;code&gt;SelectorB&lt;/code&gt; still return same result, the component subscribe to it always rerender&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;/div&amp;gt;
&amp;lt;div class="gh-btn-container"&amp;gt;&amp;lt;a class="gh-btn" href="https://github.com/facebookexperimental/Recoil/issues/924"&amp;gt;View on GitHub&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
&lt;li&gt;I have a collection contains for about 100 documents. And I tried to update 100 atoms once I received the document data, the app is hanged. The recoil and react is not smart enough to batch those update! But it turns on an idea in my head 💡 which this approach I can batch update my app which out to do lots thing and the result is incredible. I called this approach is &lt;strong&gt;Separated tree timeline&lt;/strong&gt;, and it also applicable for Redux, let's do it on the next post
&lt;img src="https://i.giphy.com/media/3ornjIhZGFWpbcGMAU/source.gif" alt="Seprated tree timeline"&gt;
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;You can not subscribe to an &lt;code&gt;atom&lt;/code&gt; value without making your component rerender. I solve that by introducing RxJS to my code, not that hard when combining them&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;The only debug tool that worked for me is &lt;code&gt;console&lt;/code&gt;. Despise there some DevTool for Recoil but it's buggy and the DX is bad&lt;/li&gt;
&lt;br&gt;


&lt;h1&gt;
  
  
  Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;⚡️ Recoil is fast and easy to use&lt;/li&gt;
&lt;li&gt;🆙 It will boost productivity by "Use &lt;code&gt;useState&lt;/code&gt; and convert it to &lt;code&gt;useRecoilState&lt;/code&gt; when needed"&lt;/li&gt;
&lt;li&gt;😤 You gonna need a strategy to struct your atoms because it will be lots more&lt;/li&gt;
&lt;li&gt;⚠️ It still lacks some support on the advantage cases, you will need help for other libs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>recoiljs</category>
    </item>
    <item>
      <title>Refi App -  A tool to make developer less painful when interacting with Firestore DB</title>
      <dc:creator>Thanh Minh</dc:creator>
      <pubDate>Tue, 30 Mar 2021 15:06:17 +0000</pubDate>
      <link>https://dev.to/thanhlm/refi-app-a-tool-to-make-developer-less-painful-when-interacting-with-firestore-db-23of</link>
      <guid>https://dev.to/thanhlm/refi-app-a-tool-to-make-developer-less-painful-when-interacting-with-firestore-db-23of</guid>
      <description>&lt;p&gt;Hello there,&lt;/p&gt;

&lt;p&gt;When I first working with FireStore I had to face many issues&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How can I filter documents by some criteria?&lt;/li&gt;
&lt;li&gt;How can I insert a new document from a JSON, in fact, I have to write a script to insert some new document&lt;/li&gt;
&lt;li&gt;I have to use GC Storge to backup the data, which is I need to spend more time learning about it. WTF 🤬 why not just export and import by a JSON file?&lt;/li&gt;
&lt;li&gt;If I edit the same field of many documents, I need to go through documents and documents to edit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is there any tool to interact with FireStore like &lt;a href="https://tableplus.com/" rel="noopener noreferrer"&gt;TablePlus&lt;/a&gt; - A question pop on my head. But you know what&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ujwRcmfHSZvjN2rld6/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ujwRcmfHSZvjN2rld6/giphy.gif" alt="Not found"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So yeah, I think many of you will phase the same issues like me, so I decided to make one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhii60utso6heuoyremzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhii60utso6heuoyremzp.png" alt="Refi App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out it at &lt;a href="https://refiapp.io/" rel="noopener noreferrer"&gt;https://refiapp.io/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;The first version includes:&lt;br&gt;
🔐 &lt;strong&gt;Privacy - Your privacy is our first priority. We do not keep any of your data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We never ever send any of your data. Your data is your and always your&lt;/p&gt;

&lt;p&gt;📜 &lt;strong&gt;Table view - Easy view &amp;amp; edit a large amount of data like Excel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🗒️ &lt;strong&gt;JSON Editor - You can add, edit documents like in your editor. No more wasted time clicking to add just a document&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We integrated &lt;code&gt;Monaco Editor&lt;/code&gt; - aka **VS Code&lt;/em&gt;* &lt;strong&gt;core&lt;/strong&gt; so you can feel like 🏠*&lt;/p&gt;

&lt;p&gt;👨‍💻 &lt;strong&gt;Build for Developer - With hotkeys, you can do anything without leaving your keyboard. We are developer, we love keyboard&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vtifw2eg9t2r0e4epe9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vtifw2eg9t2r0e4epe9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press &lt;code&gt;Cmd + Shift + P&lt;/code&gt; or &lt;code&gt;Cmd + /&lt;/code&gt; to open &lt;strong&gt;Command list&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🚧 &lt;strong&gt;Preview changes - Confidence edit data without making Production crash&lt;/strong&gt;
&lt;/h3&gt;

&lt;h2&gt;
  
  
  P/S
&lt;/h2&gt;

&lt;p&gt;This is an early version, so let help me make it better by giving me some feedback. I think we can make it better&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/26BRGxMMN3Pn1MMdG/source.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/26BRGxMMN3Pn1MMdG/source.gif" alt="Make RefiApp stronger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  P/S 2
&lt;/h2&gt;

&lt;p&gt;This tool is built by Electron, Typescript, React, Vite&lt;br&gt;
And the Homepage is built by Cloudflare worker, Notion as backend&lt;/p&gt;

&lt;p&gt;There some many interesting when building it, I think it would be shared with the community. Which one make you interesting most?&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>react</category>
    </item>
  </channel>
</rss>
