<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Marvin</title>
    <description>The latest articles on Forem by Marvin (@mfrachet).</description>
    <link>https://forem.com/mfrachet</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%2F155641%2F794ea2e4-c8ff-49ed-bdc2-bf47ecf80dd6.jpg</url>
      <title>Forem: Marvin</title>
      <link>https://forem.com/mfrachet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mfrachet"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Thu, 10 Apr 2025 18:52:42 +0000</pubDate>
      <link>https://forem.com/mfrachet/-3dff</link>
      <guid>https://forem.com/mfrachet/-3dff</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mastra_ai/build-your-first-agent-in-5-minutes-with-mastra-2ah3" class="crayons-story__hidden-navigation-link"&gt;Build your first agent in 5 minutes with Mastra&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/mastra_ai"&gt;
            &lt;img alt="Mastra AI logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F10639%2Fbb6e9abf-900b-4e45-94c0-eb8061e27b50.jpg" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/codekarate" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.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%2F3013472%2Faf07ae5a-2999-46c5-b803-5cb683a75e8c.jpg" alt="codekarate profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/codekarate" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Shane Thomas
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Shane Thomas
                
              
              &lt;div id="story-author-preview-content-2396177" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/codekarate" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.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%2F3013472%2Faf07ae5a-2999-46c5-b803-5cb683a75e8c.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Shane Thomas&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/mastra_ai" class="crayons-story__secondary fw-medium"&gt;Mastra AI&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/mastra_ai/build-your-first-agent-in-5-minutes-with-mastra-2ah3" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 10 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mastra_ai/build-your-first-agent-in-5-minutes-with-mastra-2ah3" id="article-link-2396177"&gt;
          Build your first agent in 5 minutes with Mastra
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/mastra_ai/build-your-first-agent-in-5-minutes-with-mastra-2ah3" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;32&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/mastra_ai/build-your-first-agent-in-5-minutes-with-mastra-2ah3#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              3&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            8 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Astro: progressively enhanced forms</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Thu, 09 Nov 2023 15:56:33 +0000</pubDate>
      <link>https://forem.com/mfrachet/astro-progressively-enhanced-forms-442g</link>
      <guid>https://forem.com/mfrachet/astro-progressively-enhanced-forms-442g</guid>
      <description>&lt;p&gt;&lt;em&gt;If you want to read the full article with code snippet highlighted correctly on the author's blog, &lt;a href="https://mfrachet.com/blog/en/astro-progressively-enhanced-forms"&gt;follow this link&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement"&gt;MDN documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Progressive enhancement is a design philosophy that provides a baseline of essential content and functionality to as many users as possible, while delivering the best possible experience only to users of the most modern browsers that can run all the required code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One great example of progressive enhancement is form handling in &lt;a href="https://remix.run/"&gt;Remix&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Remix, you can create an almost regular HTML form, a function called &lt;code&gt;action&lt;/code&gt;, and there you go: the form works &lt;strong&gt;with and without JavaScript&lt;/strong&gt;.&lt;br&gt;
It means that people disabling JavaScript in their browsers, or under specific constraints regarding their devices (or browsers, or low-connectivity regions) can still use the form and benefit from the feature.&lt;/p&gt;

&lt;p&gt;Some people can stand that it's probably not necessary, and I agree. The thing is: it's free. It's baked in Remix and works using the same API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Copy/pasted from the Remix doc&lt;/span&gt;
&lt;span class="c1"&gt;// about action https://remix.run/docs/en/main/route/action&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formData&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&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;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fakeCreateTodo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/todos/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;AddTodo&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;Form&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&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;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create Todo&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&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;It's a minimal API that provides a great experience to the users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remix is great, but what about &lt;a href="https://astro.build/"&gt;Astro&lt;/a&gt;?
&lt;/h2&gt;

&lt;p&gt;As you may already know, Astro is a framework for server side rendering that provides the ability to integrate frontend frameworks to get interactivity in the client. It is not the same kind of (meta) framework than &lt;a href="https://remix.run/"&gt;Remix&lt;/a&gt; or &lt;a href="https://nextjs.org/"&gt;Nextjs&lt;/a&gt;.&lt;br&gt;
And as pointed on &lt;a href="https://astro.build/"&gt;their homepage&lt;/a&gt;, the framework focuses on content websites &lt;em&gt;for now&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Basically, regarding froms, it means: use regular HTML forms or the things you have available on your client side framework (e.g: &lt;a href="https://formik.org/"&gt;formik&lt;/a&gt; on React, or whatever alternative) or build something yourself.&lt;/p&gt;

&lt;p&gt;We are going to try building something as close to what Remix provides as possible knowing that we have the following constraint: we only build user-lands. We can't tweak the inner framework implementations to accomodate our needs.&lt;/p&gt;

&lt;p&gt;It's important to have that in mind. We'll be forced to add a bit of verbosity along the way.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's get into it
&lt;/h2&gt;

&lt;p&gt;I assume you already have an Astro project running locally. If that's not the case, you can create one from &lt;a href="https://docs.astro.build/en/getting-started/"&gt;the get started page&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create an HTML form
&lt;/h3&gt;

&lt;p&gt;The first step is to create a regular HTML form that we will enhance later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
// index.astro
---
&amp;lt;main&amp;gt;
  &amp;lt;h1&amp;gt;Welcome&amp;lt;/h1&amp;gt;
  &amp;lt;form method="post"&amp;gt;
    &amp;lt;label&amp;gt;
      Email
      &amp;lt;input type="email" name="email" /&amp;gt;
    &amp;lt;/label&amp;gt;

    &amp;lt;label&amp;gt;
      Password
      &amp;lt;input type="password" name="password" /&amp;gt;
    &amp;lt;/label&amp;gt;

    &amp;lt;button&amp;gt;Sign in&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handle the form on the backend
&lt;/h3&gt;

&lt;p&gt;This will be the progressive enhancement "baseline": a form that works with regular HTML, validated and handled in the backend so that as many users as possible can use it.&lt;/p&gt;

&lt;p&gt;Additional note: this works without JavaScript on the client.&lt;br&gt;
&lt;/p&gt;

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

let error: string | undefined;

if (Astro.request.method === "POST") {
  // process form handling
  const data = await Astro.request.formData();
  const email = data.get("email")?.toString() || "";
  const password = data.get("email")?.toString() || "";

  // basic email verifications
  if (!email.includes("@domain.com")) {
    error = "Invalid email. It should contain @domain.com";
  }
}
---
&amp;lt;main&amp;gt;
  &amp;lt;h1&amp;gt;Welcome&amp;lt;/h1&amp;gt;
  {error &amp;amp;&amp;amp; &amp;lt;span&amp;gt;{error}&amp;lt;/span&amp;gt;}
  &amp;lt;!-- HTML markup for the form --&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enhancing the form client side
&lt;/h3&gt;

&lt;p&gt;The form works great but the page is flashing: when we submit the form, we make an HTTP POST request and get back an HTTP response which is basically a new, whole, document. The browser refreshes to display that new document and it creates an effect of flickering.&lt;br&gt;
This is the default behaviour when using HTML &lt;code&gt;form&lt;/code&gt; and used to work that way for decades now.&lt;/p&gt;

&lt;p&gt;There is one thing that we can do: when JavaScript is activated and loaded on the page, instead of making a regular HTML form request, we can use the &lt;code&gt;fetch&lt;/code&gt; function to submit the form. That way, we avoid the page refresh and create a feeling of interactivity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
// index.astro
// The POST handling server side
---
&amp;lt;main&amp;gt;
  &amp;lt;h1&amp;gt;Welcome&amp;lt;/h1&amp;gt;
  {error &amp;amp;&amp;amp; &amp;lt;span&amp;gt;{error}&amp;lt;/span&amp;gt;}
  &amp;lt;!-- HTML markup for the form --&amp;gt;
&amp;lt;/main&amp;gt;

&amp;lt;script&amp;gt;
  // Get the form reference
  const form = document.querySelector("form");

  if (form) {
    // listen to the submit event of the form
    form.addEventListener("submit", function (e) {
      // Avoid to page flickering and deal with the form client side
      e.preventDefault();

      // fetch the current route instead of using the HTML form submission
      fetch(form.action, {
        method: form.method,
        body: new FormData(form),
        headers: {
          accept: "application/json",
        },
      }).then((res) =&amp;gt; res.json());
    });
  }
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, if you try to submit the form, the page does not refresh anymore. If you check the &lt;code&gt;network&lt;/code&gt; tab of your browsers devtools, you should see a POST request hitting your current route but it resolves a whole a &lt;code&gt;document&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The reason is that our Astro backend only knows how to deal with regular HTML form. It doesn't know yet how to return either a whole document when the request comes from a regular HTML form or a simple JSON object when it receives a &lt;code&gt;fetch&lt;/code&gt; request.&lt;/p&gt;

&lt;p&gt;Let's modify the backend code so that it can deal with both types of requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
let error: string | undefined;

if (Astro.request.method === "POST") {
  const data = await Astro.request.formData();
  const email = data.get("email")?.toString() || "";
  const password = data.get("email")?.toString() || "";

  if (!email.includes("@domain.com")) {
    error = "Invalid email. It should contain @domain.com";
  }

  // Verify if the request comes from the client or the server
  const isClientRequest =
    Astro.request.headers.get("accept") === "application/json";

  // If it comes from the client, return a JSON response with the data
  if (isClientRequest) {
    const response = new Response(JSON.stringify({ error }));

    return response;
  }
}
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you now try to submit the form again with JavaScript enabled, with your devtools opened, you can see that the fetch request now returns a JSON object with the error. It means that we can deal with this object to update the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaning up the ground and abstracting
&lt;/h3&gt;

&lt;p&gt;It's already a bunch of code. Let's try to abstract the code from both the client and the server so that we can use it in different places easily.&lt;/p&gt;

&lt;h4&gt;
  
  
  On the client
&lt;/h4&gt;

&lt;p&gt;We only want the most necessary code to enhance the form submission with as less code as possible. We can, as one example, end up with something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  import { handleClientForm } from "./handleClientForm";

  handleClientForm(document.querySelector("form"));
&amp;lt;/script&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Let's move the content of the previous &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag into a dedicated &lt;code&gt;handleClientForm&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClientForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;form&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="c1"&gt;// listen to the submit event of the form&lt;/span&gt;
  &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Avoid to page flickering and deal with the form client side&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// fetch the current route instead of using the HTML form submission&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&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;h4&gt;
  
  
  On the server
&lt;/h4&gt;

&lt;p&gt;Same goes for the server: the idea is to move things in a dedicated &lt;code&gt;action&lt;/code&gt; function to try getting as close as possible to what Remix does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AstroGlobal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;astro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&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="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CallbackAction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AstroGlobal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;actionFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CallbackAction&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ActionReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isClientRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;accept&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// We have moved the Astro.request.formData() computations&lt;/span&gt;
    &lt;span class="c1"&gt;// outside this action function. This form checking&lt;/span&gt;
    &lt;span class="c1"&gt;// should now be done in the callback&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;actionFn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isClientRequest&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how we would use it into the page module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formData&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@domain.com&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid email. It should contain @domain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;action&lt;/code&gt; function returns two objects: a &lt;code&gt;data&lt;/code&gt; one and a &lt;code&gt;response&lt;/code&gt; one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When we submit the form using the regular HTTP way, we got back an entire document that is computed by astro with the available variables: in this case, it will use &lt;code&gt;data&lt;/code&gt; to populate the template and since &lt;code&gt;data.error&lt;/code&gt; might be filled, the template is generated accordingly.&lt;/li&gt;
&lt;li&gt;When we submit the form using JavaScript on the client, we want to get back a JSON object. We don't want Astro to generate a whole HTML document. In this case, we wrap the JSON object into a &lt;code&gt;response&lt;/code&gt; and early return it so that Astro does not try to generate a new HTML document.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Make the client code update the UI
&lt;/h3&gt;

&lt;p&gt;From the previous sections about client side code, we sent a &lt;code&gt;fetch&lt;/code&gt; request, but the UI was not updated. The reason is because the variable used in the Astro page are only available when building the page server side. Since we have shortcut this mechanism with the JSON response, we need to update the DOM manually when JavaScript kicks in.&lt;/p&gt;

&lt;p&gt;This is the limitation I was referring too at the beginning of this article.&lt;/p&gt;

&lt;p&gt;Remix wraps the whole page with a &lt;a href="https://github.com/remix-run/react-router/blob/4475b56d2e18014acfb8ff5f6077ff27df98d7fe/packages/react-router/lib/hooks.tsx#L780"&gt;React context&lt;/a&gt;. In React, context is known to work both client AND server side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if we submit the form without JavaScript, the &lt;code&gt;action&lt;/code&gt; function will be executed and its returned value will be passed to the React context &lt;strong&gt;on the server&lt;/strong&gt;. Then Remix will render the whole React tree (on the server again) and send it back as a document with the updated content.&lt;/li&gt;
&lt;li&gt;if we submit the form with JavaScript, the &lt;code&gt;action&lt;/code&gt; function is called as a &lt;code&gt;fetch&lt;/code&gt; endpoint. Remix has now access to the data &lt;strong&gt;on the client&lt;/strong&gt; and can pass it down via context. It re-renders the React tree (on the client again) and the content is updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beautiful trick.&lt;/p&gt;

&lt;p&gt;In our case, we can't do that: we don't have context in Astro. And even if we use React for our islands, the context provider should still be in our page, written by us. Plus, because of islands, the context might not work as you may think it would.&lt;/p&gt;

&lt;p&gt;With that in mind, we have different solutions and it's up to you to chose one depending on your context. They are less elegant than the Remix one.&lt;/p&gt;

&lt;p&gt;I will go with a framework agnostic one, without leveraging React or anything but instead I will rely on &lt;code&gt;data-*&lt;/code&gt; attribute to update text nodes that need to be updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!--  Let's add the data-form-id attribute so that our script can updated it --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-form-id=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{data?.error}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
      Email
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
      Password
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Sign in&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then adjust the &lt;code&gt;handleClientForm&lt;/code&gt; function to update these node when we got an answer from the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClientForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;form&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="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&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;// Get all the dom node with a data-form-id attribute&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allSlots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[data-form-id]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;allSlots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;slot&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;// For each of them get their value, which is basically the key of the data we get from the server,&lt;/span&gt;
          &lt;span class="c1"&gt;// in our case `error`&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data-form-id&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;datum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dataName&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

          &lt;span class="c1"&gt;// update the according DOM node with the value received from the fetch call&lt;/span&gt;
          &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this code, the UI will update after the fetch request is made.&lt;/p&gt;

&lt;p&gt;Of course, this blog post does not cover every single bit of form handling. It aims to be an experiment to achieve something that I find very beautiful in another framework.&lt;/p&gt;

&lt;p&gt;If you want to play with it in Stackblitz, give it a look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/edit/withastro-astro-lgq9es?embed=1&amp;amp;file=src%2Fpages%2Findex.astro"&gt;https://stackblitz.com/edit/withastro-astro-lgq9es?embed=1&amp;amp;file=src%2Fpages%2Findex.astro&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>astro</category>
      <category>react</category>
    </item>
    <item>
      <title>10 things about feature flags that will speed-up your workflow</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Wed, 26 Jul 2023 08:33:10 +0000</pubDate>
      <link>https://forem.com/mfrachet/10-things-about-feature-flags-that-will-speed-up-your-workflow-2mhl</link>
      <guid>https://forem.com/mfrachet/10-things-about-feature-flags-that-will-speed-up-your-workflow-2mhl</guid>
      <description>&lt;p&gt;I used to work painfully with &lt;a href="https://progressively.app/blog/is-gitflow-really-needed"&gt;Gitflow and feature branches&lt;/a&gt; until I realised that what I really needed was &lt;a href="https://trunkbaseddevelopment.com/"&gt;Trunk based Development&lt;/a&gt; and &lt;strong&gt;feature flags&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Don't forget that the goal of a developer is to ship value and Gitflow/feature branches were slowing me down in this regard.&lt;/p&gt;

&lt;p&gt;With trunk based development, I create very small branches that lives for a few hours, and each time I merge one in the main branch, the code is deployed to production. To protect users from accessing unfinished features, I use feature flags: each time I want to activate a feature, I just press a button.&lt;/p&gt;

&lt;p&gt;How fast is that?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are 10 things about feature flags that will speed-up your workflow.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Separate code deployment from feature releases
&lt;/h2&gt;

&lt;p&gt;You can deploy code 20 times a day, and all this code may not act as a fully polished feature. And it's okay because with feature flags, activating a feature to the audience is not tightly bound to your code deployment process: it's just a toggle button that you click in a dashboard to make the feature available to the users.&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newFeature&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NewFeature&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OldFeature&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Rollbacks are easy
&lt;/h2&gt;

&lt;p&gt;Almost the same point as above: since the code deployed and the feature are not strictly bound, you can deactivate the feature with just one click and not go through your whole CI/CD pipelines to get back to a valid and running state.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Test directly in production
&lt;/h2&gt;

&lt;p&gt;In most of the feature flags tools available in the market,  you can decide which users can see the new feature and which users can't. It means that you can activate the feature only for your QA team and they will be able to play directly in production.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Side effect: no discrepancies between environment anymore, it's always the same servers configurations.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Unlock Canary and Beta releases
&lt;/h2&gt;

&lt;p&gt;Using the same targeting tooling as previously explained, you can create a Canary users group and a Beta users group and activate the feature very early for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Gradual rollout
&lt;/h2&gt;

&lt;p&gt;Let's say you've built a brand new feature, and you don't feel very confident about what you've created. With feature flagging tools, you can increasingly rollout your feature to 1%, 2%, 3%...100% of your audience.&lt;/p&gt;

&lt;p&gt;Funny thing is that you can correlate the percentage of rollout with your error tracking tool (such as Sentry) and check if your new feature has increased your error rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The A/B testing side effect
&lt;/h2&gt;

&lt;p&gt;Feature flags are generally used with "true" and "false" values: is the feature activated or not?&lt;/p&gt;

&lt;p&gt;By pushing the concept one step further, we can give feature flags multiple values "A", "B", "C" (or whatever) and display different UI/UX of a given feature to a percentage of the audience. You can then measure the amount of actions taken on each of these different views and see which one converts the most.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Time based rollout
&lt;/h2&gt;

&lt;p&gt;You have something to deploy on Monday at 9am? With feature flagging tools, you can automate that. Since, again, the feature and the code are not tightly bound, the code already exists in production: all you need to do is to create a rule in the dashboard of your tool and at 9am Monday, you'll see your new feature live.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. No impact on web performance with &lt;a href="https://progressively.app/"&gt;Progressively&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Progressively is a feature flagging tool and in contrary to other solutions, the client side SDK, that works in real-time, is only 1.3kB.&lt;/p&gt;

&lt;p&gt;Stop fearing the slow page loading because of third party tools anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. &lt;a href="https://progressively.app/"&gt;Progressively&lt;/a&gt; with SSR and Edge Runtimes
&lt;/h2&gt;

&lt;p&gt;The tool works with SSR frameworks such as Svelte, Qwik, Astro, Nextjs, Remix etc... You don't need to wait for the client side of your app to load and the page to flicker to benefit from a great experience with feature flags.&lt;/p&gt;

&lt;p&gt;And if you want to work at an even bigger scale, try to use Progressively inside an Edge Middleware in Vercel ;).&lt;/p&gt;

&lt;h2&gt;
  
  
  10. &lt;a href="https://progressively.app/"&gt;Progressively&lt;/a&gt; is FREE
&lt;/h2&gt;

&lt;p&gt;It's open source, and you can self-host it on your own servers. Go to &lt;a href="https://github.com/progressively-crew/progressively"&gt;https://github.com/progressively-crew/progressively&lt;/a&gt;, follow the instruction and spawn your instance on your own machine, for free.&lt;/p&gt;

&lt;p&gt;And if you're not so much on self-hosting, there is a SaaS solution that you can pay to play with.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>react</category>
    </item>
    <item>
      <title>The page flickering when using feature flags and A/B testing tools</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Mon, 12 Dec 2022 14:01:06 +0000</pubDate>
      <link>https://forem.com/mfrachet/the-page-flickering-when-using-feature-flags-and-ab-testing-tools-4l3j</link>
      <guid>https://forem.com/mfrachet/the-page-flickering-when-using-feature-flags-and-ab-testing-tools-4l3j</guid>
      <description>&lt;p&gt;As developers, we constantly strive to improve our applications. We fix bugs, implement new features, and prioritize user experience. These updates and enhancements are critical for the success of our applications and need to be rolled out in a timely manner.&lt;/p&gt;

&lt;p&gt;Feature flags are an effective tool for minimizing risk and reducing lead time. By creating code behind a flag, we can seamlessly deploy updates and toggle the flag when the new feature is ready for release. This allows us to quickly and easily make changes to our applications without disrupting the user experience.&lt;/p&gt;

&lt;p&gt;As with any technology, there are limitations to using feature flags (or A/B testing) in JavaScript applications, including those built with the JAMStack. One common issue that can arise is “page flickering,” which can be frustrating for both developers and users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Page Flickering Problem”
&lt;/h2&gt;

&lt;p&gt;Let me illustrate what is the “page flickering” problem:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ft4hdhfvelbt7sz209tya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ft4hdhfvelbt7sz209tya.png" alt="Timeline of a feature flag resolution" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The previous picture illustrates what happens when using feature flags (or A/B tests) in a classical JavaScript application, including JAMStack ones. Here are some explanations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A user makes a request to a website&lt;/li&gt;
&lt;li&gt;  They get back the &lt;strong&gt;/index.html&lt;/strong&gt; file of it (empty for client only application, and already filled for JAMStack applications)&lt;/li&gt;
&lt;li&gt;  The browser parses the HTML file and prepares every scripts it has inside&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The website is now visible (empty or filled)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  The frontend application kicks in and the site is interactive&lt;/li&gt;
&lt;li&gt;  The JavaScript application fetches the feature flags from the according (remote) service&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;It gets back the flags and updates the application, showing the new version with / without the flag.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the previous picture, two bold-ish red squares are highlighted. Their written equivalences, which are also highlighted in bold, are explained in the text above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My question is:&lt;/strong&gt; For the end user, what happens between the moment the page is displayed and the moment when the flag resolves?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The answer:&lt;/strong&gt; The old version, UI is moving, the new version, in that order.&lt;/p&gt;

&lt;h2&gt;
  
  
  How people generally mitigate this behaviour?
&lt;/h2&gt;

&lt;p&gt;Hopefully, there are multiple solutions available on the internet to deal with feature flags so that you don’t have to (such as &lt;a href="https://progressively.app/" rel="noopener noreferrer"&gt;Progressively&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Spinners, loading indicators
&lt;/h3&gt;

&lt;p&gt;To address the problem illustrated in the previous picture, one solution is to hide all the website’s content during the flag resolution and display a spinner or loading indicator. On subsequent page loads, the browser storage can be used to quickly show the correct variation and adjust over time.&lt;/p&gt;

&lt;p&gt;While this solution may be suitable for applications and dashboards, it may not be the best approach for marketing websites where we want the pages to load instantly. In these cases, hiding the website’s content and displaying a spinner or loading indicator may not be acceptable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shifting resolution to the infrastructure layer
&lt;/h3&gt;

&lt;p&gt;Upon closer examination, we can see that the problem stems from the fact that applications only run after the browser has already displayed the page to the user. Specifically, the &lt;code&gt;script&lt;/code&gt; tags in the HTML document are only executed when the HTML document is loaded in the browser. This results in a delay between the time the user sees the page and the time the flag resolves.&lt;/p&gt;

&lt;p&gt;However, there are things that run &lt;em&gt;before&lt;/em&gt;, even if we don’t rely on a dedicated server that renders pages (think server side rendering).&lt;/p&gt;

&lt;p&gt;The infrastructure layer is a place where we can do things, ahead of time.&lt;/p&gt;

&lt;p&gt;I’ve written a post, some time ago, about &lt;a href="https://mfrachet.github.io/a-b-testing-with-the-jamstack/" rel="noopener noreferrer"&gt;A/B testing with the JAMStack and how we can achieve this at the infrastructure layer&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Server Side Rendering
&lt;/h3&gt;

&lt;p&gt;By recognizing that the problem is caused by running the flag resolution in the browser, we can instead move this resolution back to the server.&lt;/p&gt;

&lt;p&gt;With tools like Next.js, Remix, or any other framework that supports it, you can generate the valid HTML document for each request, with the content behind a flag variant already resolved.&lt;/p&gt;

&lt;p&gt;Progressively can also assist in this situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would be the best way to fix this issue?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This is subjective, and my personal opinion. It mostly target situations with high traffic where hitting the server hosting the application might cost a bunch of money.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just as I design APIs by first defining the desired outcome and then implementing the details, I will first specify what I want and how to achieve it, keeping in mind that client-side only and JAMStack applications may not behave as desired. This approach allows me to design the solution before diving into the details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I want:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A website that does not blink&lt;/li&gt;
&lt;li&gt;  A website that does not cost a lot of money&lt;/li&gt;
&lt;li&gt;  A fast website&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A website that does not blink
&lt;/h3&gt;

&lt;p&gt;One solution to this problem is to use a technology that employs Server Side Rendering. With this approach, the page is generated on the server and delivered to the user in its completed form, allowing for instant display in the browser. This can greatly improve the loading speed and overall performance of the site.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My preferences for my ideal world would be Next.js, I will explain why, but you can use any tool that supports SSR, it will work great.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A website that does not cost a lot of money
&lt;/h3&gt;

&lt;p&gt;The JAMStack is truly amazing, especially when paired with a free CDN like Github Pages. Plus, it won’t cost a dime!&lt;/p&gt;

&lt;p&gt;But on the other hand, the use of a Server Side Rendering tool would require some expenditure. However, with the help of a CDN and aggressive caching of requests to reduce the load on the origin server, which is the costly part, it can be made affordable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;1, 2, 3…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The introduction of the CDN has just broken the feature flags functionality. This is because the CDN caching is applied at the URL level, so when requesting &lt;a href="https://website.com/" rel="noopener noreferrer"&gt;https://website.com/&lt;/a&gt;, all the audience will receive the last version cached by the CDN.&lt;/p&gt;

&lt;p&gt;However, it exists solutions such as &lt;a href="https://vercel.com/docs/concepts/functions/edge-middleware" rel="noopener noreferrer"&gt;Edge Middlewares in Vercel&lt;/a&gt; that allow to run code &lt;em&gt;before&lt;/em&gt; reaching the CDN cache, at the edge. And this is a perfect place to resolve the feature flag (and A/B tests) variants.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are interested,&lt;/em&gt; &lt;a href="https://dev.to/mfrachet/feature-flags-at-the-edge-with-progressively-and-vercel-recipe-4hj0"&gt;&lt;em&gt;this blog post&lt;/em&gt;&lt;/a&gt; &lt;em&gt;shows how to use Progressively and Vercel Edge Middleware together.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A fast website
&lt;/h3&gt;

&lt;p&gt;A Server Side application is now being run at the edge on Vercel, with feature flags being handled at the edge using Edge Middleware and cached by a CDN.&lt;/p&gt;

&lt;p&gt;This technology stack is known for its speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The last mile
&lt;/h3&gt;

&lt;p&gt;Remember my decision to use Next.js earlier? The reason is because, as mentioned earlier, CDN caching can only work at the URL level, and the same is true for edge middlewares. You can’t modify the internal of the document in edge middlewares since they run before the CDN cache.&lt;/p&gt;

&lt;p&gt;But one interesting thing that came in Next.js 13, are the support of React Server Components (RSCs). As the name suggests, RSCs run on a server, somewhere, and are probably available through a URL.&lt;/p&gt;

&lt;p&gt;What if, in the future, Edge Middlewares were able to process only requests that would aim to resolve RSCs?&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Feature flags at the edge with Progressively and Vercel (recipe)</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Wed, 23 Nov 2022 06:59:07 +0000</pubDate>
      <link>https://forem.com/mfrachet/feature-flags-at-the-edge-with-progressively-and-vercel-recipe-4hj0</link>
      <guid>https://forem.com/mfrachet/feature-flags-at-the-edge-with-progressively-and-vercel-recipe-4hj0</guid>
      <description>&lt;p&gt;&lt;em&gt;There is a glossary at the end of the article if you are not used to these terms.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you don't want to set up the whole thing, a Nextjs application showcasing this is available on &lt;a href="https://github.com/mfrachet/progressively-edge-middleware"&gt;https://github.com/mfrachet/progressively-edge-middleware&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧀 Ingredients&lt;/li&gt;
&lt;li&gt;
👨‍🍳 Directions

&lt;ul&gt;
&lt;li&gt;1. Create a feature flag in Progressively&lt;/li&gt;
&lt;li&gt;2. Create feature flag variants&lt;/li&gt;
&lt;li&gt;3. Create a Nextjs project&lt;/li&gt;
&lt;li&gt;4. Create pages matching the previously created variants&lt;/li&gt;
&lt;li&gt;5. Install Progressively sdk&lt;/li&gt;
&lt;li&gt;6. Create the middleware file&lt;/li&gt;
&lt;li&gt;7. Push the code on GitHub&lt;/li&gt;
&lt;li&gt;8. Run the project on Vercel&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
📚 Glossary

&lt;ul&gt;
&lt;li&gt;Feature flags&lt;/li&gt;
&lt;li&gt;Progressively&lt;/li&gt;
&lt;li&gt;Vercel Edge Middleware&lt;/li&gt;
&lt;/ul&gt;


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




&lt;h2&gt;
  
  
  🧀 Ingredients
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A running instance of &lt;a href="https://progressively.app/docs/introduction/getting-started"&gt;Progressively&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A personal Github account on &lt;a href="https://vercel.com/dashboard"&gt;Vercel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; &amp;gt; 16&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  👨‍🍳 Directions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create a feature flag in Progressively
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a new project in the dashboard of Progressively (&lt;code&gt;/dashboard/projects/create&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Production&lt;/code&gt; environment that has been created&lt;/li&gt;
&lt;li&gt;Keep the environment key close, we'll need it in the next step.&lt;/li&gt;
&lt;li&gt;Click the &lt;code&gt;Create a feature flag&lt;/code&gt; button and fill out the form&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Create feature flag variants
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Once the flag is created, click on its name in the table&lt;/li&gt;
&lt;li&gt;On the feature flags page, Click on &lt;code&gt;Variants&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add 3 variants named &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;C&lt;/code&gt;, and adjust the percentage to your taste&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Create a Nextjs project
&lt;/h3&gt;

&lt;p&gt;Run the following command somewhere on your computer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Create pages matching the previously created variants
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;./pages&lt;/code&gt; folder, create three files called &lt;code&gt;index.ts&lt;/code&gt;, &lt;code&gt;b.ts&lt;/code&gt;, and &lt;code&gt;c.ts&lt;/code&gt; with different content inside.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Install Progressively sdk
&lt;/h3&gt;

&lt;p&gt;Run the following command at the root of your Nextjs project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @progressively/server-side
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Create the middleware file
&lt;/h3&gt;

&lt;p&gt;At the root of your Nextjs project, create a &lt;code&gt;middleware.ts&lt;/code&gt; (or &lt;code&gt;.js&lt;/code&gt;, depending on your preferences) and copy the following code in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getProgressivelyData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@progressively/server-side&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;PROGRESSIVELY_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT YOUR SERVER URL HERE&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;PROGRESSIVELY_ENV&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT THE ENVIRONMENT KEY HERE&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;ExperimentRoutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/c&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;type&lt;/span&gt; &lt;span class="nx"&gt;ExperimentRoutesKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;ExperimentRoutes&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the user ID from cookies in order to always show them the same variant&lt;/span&gt;
  &lt;span class="c1"&gt;// If showing the same variant to the same user every time is not a concern for you, you can remove this line&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progressively-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the feature flags from Progressively&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getProgressivelyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PROGRESSIVELY_ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PROGRESSIVELY_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Checking that the progressively servers brings us a valid first user id&lt;/span&gt;
  &lt;span class="c1"&gt;// If showing the same variant to the same user every time is not a concern for you, you can remove this line&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;progressivelyId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-progressively-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;progressivelyId&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nextRawUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;ExperimentRoutes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newHero&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ExperimentRoutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A&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;nextUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rewrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextRawUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Stick the user ID to the cookies in order to always show them the same variant&lt;/span&gt;
  &lt;span class="c1"&gt;// If showing the same variant to the same user every time is not a concern for you, you can remove this line&lt;/span&gt;
  &lt;span class="nx"&gt;nextUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progressively-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;progressivelyId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nextUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;matcher&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;/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Push the code on GitHub
&lt;/h3&gt;

&lt;p&gt;Create a repository on &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; and push the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Run the project on Vercel
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Connect to your &lt;a href="https://vercel.com/dashboard"&gt;Vercel&lt;/a&gt; account using GitHub&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Add a new...&lt;/code&gt; and then &lt;code&gt;Project&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Continue with Github&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select your repository and click &lt;code&gt;Import&lt;/code&gt; at the end of the line&lt;/li&gt;
&lt;li&gt;Fill out the form and click &lt;code&gt;Deploy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have a Nextjs application, working on the edge using feature flags in Progressively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB: if you want to see the different variants when refreshing, make sure to clean your cookies 😉&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Glossary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Feature flags
&lt;/h3&gt;

&lt;p&gt;Feature flags are a technic allowing to progressively rollout features without modifying code at the moment of the release. &lt;br&gt;
They generally take the form of a switch button that you can toggle on and off.&lt;/p&gt;

&lt;p&gt;For instance, you may have created a new fancy UI for your login page, but you want to make sure you don't have errors on it that could block your users from accessing your platform. With a feature flagging tool, you can show this new page to N% of your audience, and augment this percentage while you acquire confidence until everybody sees the new page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Progressively
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://progressively.app/"&gt;Progressively&lt;/a&gt; is a free, simple, accessible, lightweight, self-hosted and Open Source feature flagging tool that you can use to rollout features to your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vercel Edge Middleware
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://vercel.com/docs/concepts/functions/edge-middleware"&gt;Vercel Edge Middleware&lt;/a&gt; is code that executes before a request is processed on a site, and before the CDN cache is hit. &lt;/p&gt;

&lt;p&gt;They are a very conveniant place to handle A/B testing and feature flagging using page redirections, without content flashes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>nextjs</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A/B tests &amp; feature flags, what do you love and what do you hate?</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Tue, 22 Nov 2022 15:04:11 +0000</pubDate>
      <link>https://forem.com/mfrachet/ab-tests-feature-flags-what-do-you-love-and-what-do-you-hate-2ieg</link>
      <guid>https://forem.com/mfrachet/ab-tests-feature-flags-what-do-you-love-and-what-do-you-hate-2ieg</guid>
      <description>&lt;p&gt;Hey folks,&lt;/p&gt;

&lt;p&gt;I m a huge fan of feature flags and technics allowing to ship features more efficiently to the users.&lt;/p&gt;

&lt;p&gt;And I m very interested to hear your stories on how you use these tools to ship better features for your audience.&lt;/p&gt;

&lt;p&gt;What is the most interesting metric that you rely on and that tells you "hey, this is what we should provide to the users"&lt;/p&gt;

&lt;p&gt;Let me know everything about your experiences!&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>A/B testing with the JAMstack</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Tue, 28 Dec 2021 08:03:45 +0000</pubDate>
      <link>https://forem.com/mfrachet/ab-testing-with-the-jamstack-22mp</link>
      <guid>https://forem.com/mfrachet/ab-testing-with-the-jamstack-22mp</guid>
      <description>&lt;p&gt;The JAMstack has been talked about in recent years like a way to create static websites that scales very well in many different ways.&lt;br&gt;
Since it becomes more and more mainstream, it made sense to people to think about how to apply older patterns that we like in this&lt;br&gt;
quite particular context.&lt;/p&gt;

&lt;p&gt;In this post, I will share with you &lt;strong&gt;my vision&lt;/strong&gt; of A/B testing (or feature flagging, everything written below may apply to both) using the JAMstack.&lt;/p&gt;
&lt;h2&gt;
  
  
  But first, why do we use the JAMstack?
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://jamstack.org/" rel="noopener noreferrer"&gt;jamstack.org&lt;/a&gt;, we use it because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's about building &lt;strong&gt;simple static pages&lt;/strong&gt; (HTML files)&lt;/li&gt;
&lt;li&gt;most of the job is made at build-time, no potential leak at runtime, it's more &lt;strong&gt;secured&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;static pages are basically HTML files and thus &lt;strong&gt;load very fast&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;we benefit from &lt;strong&gt;cheap hosting&lt;/strong&gt; (putting files on a server and there we go)&lt;/li&gt;
&lt;li&gt;it's &lt;strong&gt;highly scalable&lt;/strong&gt;, just put the files on another machine and scaling is done&lt;/li&gt;
&lt;li&gt;it already exists great tools to create amazing sites (&lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsbyjs&lt;/a&gt;, &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Nextjs&lt;/a&gt;, &lt;a href="https://www.11ty.dev/" rel="noopener noreferrer"&gt;11ty&lt;/a&gt;, &lt;a href="https://jamstack.org/generators/" rel="noopener noreferrer"&gt;etc...&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why do we use A/B testing?
&lt;/h2&gt;

&lt;p&gt;People use A/B testing to measure which variant of a website is more appreciated by their users. The idea is simply to provide different visual representations of some data and check which one attracts more people.&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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fab-tests.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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fab-tests.png" alt="Visual representation of two different variants of an A/B tests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the visitors of the variant A come more often than the visitors of the variant B, then we can assume that variant A is a more viable solution to represent the data on the page.&lt;/p&gt;
&lt;h2&gt;
  
  
  How do we use A/B testing in non JAMstack applications?
&lt;/h2&gt;

&lt;p&gt;In applications that are not built on top of the JAMstack, the idea is quite straightforward.&lt;/p&gt;

&lt;p&gt;When opening the application, it will make a request to a remote server to get the different available variants. Then, based on some conditions in the codebase, we are able to display the good variant to the good user.&lt;/p&gt;

&lt;p&gt;The following is an example of a client-side A/B test written with &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;Reactjs&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useABVariant&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Preparing the application...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&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="k"&gt;return&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;Here's the A variant!&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="k"&gt;return&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;Here's the B variant!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we see in the snippet, the code is executed in the user's browser. Also notice &lt;strong&gt;the loading information while the request is pending&lt;/strong&gt; before being able to display the variant content.&lt;/p&gt;

&lt;p&gt;The following is a tiny sandbox allowing to switch on and off a feature flag to display a new variant of a homepage. When using services like &lt;a href="https://launchdarkly.com/" rel="noopener noreferrer"&gt;LaunchDarkly&lt;/a&gt;, this is exactly the kind of actions you're provided with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why A/B testing on the JAMstack is different?
&lt;/h2&gt;

&lt;p&gt;Remember one of the main arguments of building on top of the JAMstack is &lt;strong&gt;fast page loading&lt;/strong&gt; (performance).&lt;/p&gt;

&lt;p&gt;When dealing with A/B tests the "standard way", &lt;strong&gt;we need to make an HTTP request to get the different variants&lt;/strong&gt;. Making an HTTP request means that &lt;strong&gt;there is a delay&lt;/strong&gt; between the moment we ask for the variants and the moment we get them back from the server.&lt;/p&gt;

&lt;p&gt;The problem is that &lt;strong&gt;making the HTTP request is so critical&lt;/strong&gt; that we can't show anything else than a loading information to the user before resolving the variants and being able to show them the good content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a static environment, we are waiting for a dynamic information to display meaningful information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When A/B testing the "standard way", using runtime information will &lt;strong&gt;make the application performances worse by increasing the time for displaying the first meaningful content&lt;/strong&gt;. Loading static pages should be "instant" but relying on an HTTP request and an intermediate loading state before displaying the content will take extra time and decrease the experience.&lt;/p&gt;

&lt;p&gt;In some scenarios, &lt;a href="https://developers.google.com/web/tools/lighthouse" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt; performance score can drop by around &lt;code&gt;25&lt;/code&gt; points (up to you to determine if it's significant or not).&lt;/p&gt;

&lt;p&gt;Also note that some tools helping building applications using the JAMstack &lt;strong&gt;don't even run JavaScript at all&lt;/strong&gt;, meaning that it's not possible to rely on HTTP requests to access remote data at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to make A/B testing in a JAMstack fashion?
&lt;/h2&gt;

&lt;p&gt;The JAMstack is about &lt;strong&gt;building static pages&lt;/strong&gt;. Taking this notion to the extreme, we can imagine creating a dedicated set of static pages for different variants and host them in different places, like for example, different machines.&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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fmachine-ab.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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fmachine-ab.png" alt="Visual representation of two machines hosting two different variants of an A/B test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The machine 1&lt;/strong&gt; owns all the statically generated HTML pages impacted by the variant A and &lt;strong&gt;the machine 2&lt;/strong&gt; owns all of the statically generated HTML pages of the variant B.&lt;/p&gt;

&lt;p&gt;Since pages are statically generated at build time, we can rely on environment variables to display the good variant content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AB_EXPERIMENT_VARIANT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AB_EXPERIMENT_VARIANTS&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;App&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AB_EXPERIMENT_VARIANT&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&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="k"&gt;return&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;Here's the A variant!&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="k"&gt;return&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;Here's the B variant!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to rely on some kind of proxy to route the different users to one of the two variants and make sure they always see that variant.&lt;/p&gt;

&lt;p&gt;Remember, &lt;strong&gt;we can't rely on runtime information to store the variant&lt;/strong&gt;, like an authenticated user id for example. We need to rely on something else. Hopefully, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies" rel="noopener noreferrer"&gt;HTTP Cookies&lt;/a&gt; exist that allow for a client-server kind of data sharing. We can benefit from them to store the actual variant requested by the user and make sure that they will always get routed to that variant.&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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fcookie-ab.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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fcookie-ab.png" alt="Visual representation of a proxy routing an HTTP request to the good machine for an A/B test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Observations on this approach
&lt;/h2&gt;

&lt;p&gt;The first observations to push upfront is that &lt;strong&gt;we have kept the page loading performances provided by default by the JAMstack&lt;/strong&gt;. We don't have to wait for runtime computations to display content on the page.&lt;/p&gt;

&lt;p&gt;The second observation is about the tradeoffs we decided to make: we shifted the A/B testing responsibility &lt;strong&gt;closer to the infrastructure layer&lt;/strong&gt;. The proxy has an important role to play in this scenario.&lt;/p&gt;

&lt;p&gt;Also note that we need more "places" to put the different variants: 1 variant corresponds to 1 website that corresponds to 1 set of static pages that should entirely be hosted. &lt;strong&gt;The more we have variants, the more we may pay for hosting&lt;/strong&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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fall-variants.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%2Fmfrachet.github.io%2Fblog%2Fa-b-testing-with-the-jamstack%2Fall-variants.png" alt="A visual representation of a project having 4 different variants"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's also one side effect that I find positive (but it can feel negative) is that it can be hard to combine multiple A/B experiments.&lt;/p&gt;

&lt;p&gt;Let's say that we have 2 pages and that we want to run an experiment on both the pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What can be a visual representation of these scenarios at the hosting level?&lt;/li&gt;
&lt;li&gt;Should we create 4 different websites, one for each variant?&lt;/li&gt;
&lt;li&gt;Should we create N different websites with combinations of variants?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My expectations is that there will be solutions allowing to make A/B testing at the file level itself, and not at that site level.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;If you're using &lt;a href=""&gt;Netlify&lt;/a&gt; for hosting your websites, they have a feature called &lt;a href="https://docs.netlify.com/site-deploys/split-testing/" rel="noopener noreferrer"&gt;Split-testing&lt;/a&gt; that allows for these kind of testing using a branch based approach.&lt;/p&gt;

&lt;p&gt;If you have any other references in mind concerning A/B testing or Split Testing on top of the JAMstack, feel free to drop them on &lt;a href="https://twitter.com/mfrachet" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>testing</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Right in my dev shoes</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Thu, 22 Apr 2021 08:10:28 +0000</pubDate>
      <link>https://forem.com/mfrachet/right-in-my-dev-shoes-24og</link>
      <guid>https://forem.com/mfrachet/right-in-my-dev-shoes-24og</guid>
      <description>&lt;p&gt;Working in the web industry is like a gift and a curse to me. On one side, I'm increasing my situation and making money doing something that I love and on the other side, I'm seeing an increasing amount of things that I don't agree with but that becomes quite the norm — and it feels bad to be part of that without doing anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why am I feeling that way?
&lt;/h2&gt;

&lt;p&gt;Earning money when running a business is, hopefully, normal and evident. Earning more money every year is a sign of good health for a company. Problems arise when, to make money, &lt;strong&gt;people cross the ethical frontiers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The following is a non-exhaustive list of questions that raises ethical problems to me and that I would like to share with you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many companies gather personal information about people to compute them and make money from them?&lt;/li&gt;
&lt;li&gt;How many of those companies are considered examples for younger developers?&lt;/li&gt;
&lt;li&gt;How many women are less paid than their men peers?&lt;/li&gt;
&lt;li&gt;How many people don't have valid experience on the web because of inaccessible content?&lt;/li&gt;
&lt;li&gt;How much energy do we spend running all those services in the cloud?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every single question in this list deserves an entire book to get proper answers.&lt;/p&gt;

&lt;p&gt;Keep in mind that this post is not about blaming people that are not aware of the problems. &lt;strong&gt;It aims to make them realize that these things are not okay per se&lt;/strong&gt; and that they should be addressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix that?
&lt;/h2&gt;

&lt;p&gt;The answer is simple on the paper, but very hard in practice: &lt;strong&gt;we have to care&lt;/strong&gt;. It's not about just knowing and putting the problems somewhere in our heads and "remembering to tackle them later". &lt;strong&gt;We have to be aware and act concretely&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing tools and services that respect people's privacy
&lt;/h3&gt;

&lt;p&gt;For instance, if we need to get audience information about our websites, what about using &lt;strong&gt;tools that respect people's privacy&lt;/strong&gt;? &lt;a href="https://plausible.io/"&gt;Plausible.io&lt;/a&gt; is one of them and it allows to get that information without the need for private data (there are others, it's just the one that I use, I don't have any bindings with the company).&lt;/p&gt;

&lt;p&gt;On the consumer side, if you don't agree with some companies' policies (&lt;a href="https://wicg.github.io/floc/"&gt;you may have heard of some kind of new tracking technics recently&lt;/a&gt;), &lt;a href="https://www.privacytools.io/"&gt;Privacy Tools&lt;/a&gt; is a great website giving practical advice, suggesting services and tools to reduce your privacy exposure.&lt;/p&gt;

&lt;p&gt;We're not forced to use (or to be the victims of) tools from mastodons that keep track of &lt;strong&gt;users' moves, through our websites, making us at least, partially responsible.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Equity
&lt;/h3&gt;

&lt;p&gt;The second point is about gender equity — and I should say equity in general.&lt;/p&gt;

&lt;p&gt;If by any means, we spot a salary discrepancy between two people doing the same job, discrimination, or even harassment, &lt;strong&gt;we have to bring the problem up&lt;/strong&gt;. We're not forced to react intensely, we can gently raise the flag and create a discussion. &lt;strong&gt;But it's important to raise that flag&lt;/strong&gt;. We have to communicate, try to understand and find a way to fix the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We should not hesitate to be vocal and to support our colleagues&lt;/strong&gt; when they need us, let's offer them our help, and manifest ourselves to improve the situation. Multiple voices have more impact than a single one from a person that faces professional difficulties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hiding and keeping information because we don't feel concerned (or not comfortable) is selfish and unethical. It contributes somehow to keeping this problem real but also hidden.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Embracing Accessibility
&lt;/h3&gt;

&lt;p&gt;The third point is about accessibility. I can't say how grateful I am to have been introduced to it by &lt;a href="https://twitter.com/amber1ey"&gt;Amberley&lt;/a&gt; and &lt;a href="https://twitter.com/madalynrose"&gt;Madalyn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One amazing effect of accessibility is that when you learn enough of it, you immediately become an advocate and can't do without it. Accessibility is an ethical topic where &lt;strong&gt;everybody&lt;/strong&gt; should be provided with a frictionless user experience when using a service or a tool — and it does not only apply to people that can &lt;em&gt;see&lt;/em&gt; what's happening on a screen.&lt;/p&gt;

&lt;p&gt;The biggest problem with accessibility, to me, is that &lt;strong&gt;the number of people who have already built a truly accessible website is very low&lt;/strong&gt;. I don't blame anyone for not having this knowledge, I have personally never heard of it in school nor during my first 6 years working in the industry. But it's important to be aware of it, to educate ourselves, and to learn more about it.&lt;/p&gt;

&lt;p&gt;If you're not familiar with accessibility, I suggest reading &lt;a href="https://dev.to/hichamelbsi/accessibility-is-a-priority-3jbf"&gt;Accessibility is a priority&lt;/a&gt; published by one of my colleagues that provides practical wins to make your website more accessible. Also, I highly recommend spending time on &lt;a href="https://a11y.coffee/"&gt;A11y Coffee&lt;/a&gt; to completely dive into the topic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We have to keep in mind that making our websites more accessible is a game-changer for more people than we think, we and our companies included. Not making this is, to me, as serious as discriminating a whole population&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecology, green IT
&lt;/h3&gt;

&lt;p&gt;The last point of my bullet list is about energy consumption.&lt;/p&gt;

&lt;p&gt;It's a very tough topic since our job is to build things running on electrical devices and so, our creations consume a certain amount of energy, often time 24/7. &lt;strong&gt;We live in an era of over-consumption and as technical people, we love innovation. The thing is, sometimes, innovation creates more indirect or invisible problems than it solves&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We obviously have to change the way we consume, reducing wasting, &lt;strong&gt;making sure our electronic devices (that are built using a gigantic amount of natural resources) reach their lifespan&lt;/strong&gt; before getting new ones.&lt;/p&gt;

&lt;p&gt;Concerning our web creations, two things can be done to reduce their footprints: &lt;strong&gt;hosting them on a "Green Hosting" provider that has a low &lt;a href="https://en.wikipedia.org/wiki/Power_usage_effectiveness"&gt;PUE&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;using the right tools for the right job&lt;/strong&gt;. What would be the real advantages of building a blog with a server-side technology on a whole Kubernetes cluster to only serve a few posts?&lt;/p&gt;

&lt;p&gt;Also, if you come from the React ecosystem, I've written a post about &lt;a href="https://mfrachet.github.io/blog/choosing-a-rendering-strategy/"&gt;the different rendering strategies I would adopt depending on the circumstances&lt;/a&gt; that help me &lt;strong&gt;avoiding server-side rendering when I don't need it&lt;/strong&gt;. And for French people, &lt;a href="https://www.greenit.fr"&gt;Green It&lt;/a&gt; proposes workshops and books about improving website footprints at the code level.&lt;/p&gt;

&lt;p&gt;On the auditing side, I've recently discovered two tools to measure, or at least to provide an order of growth, of the energy consumed by a website: &lt;a href="https://www.websitecarbon.com/"&gt;WebsiteCarbon&lt;/a&gt; and &lt;a href="https://github.com/marmelab/argos"&gt;Argos&lt;/a&gt;. I don't have that much feedback on them but the intent deserves at least respect and encouragement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.bbc.com/future/article/20200305-why-your-internet-habits-are-not-as-clean-as-you-think"&gt;The internet accounts for around 4% of the greenhouse gas emissions which is the same amount as the whole airline industry.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Educating, teaching, learning
&lt;/h3&gt;

&lt;p&gt;I voluntarily skipped the second point in the list and it's, for me, probably the most important.&lt;/p&gt;

&lt;p&gt;Younger developers may dream of fame and be part of an elite, wanting to join big companies because "they are the place to be". There is nothing wrong with that but there are some correlations between some topics addressed in this post and some companies that people are dreaming to join.&lt;/p&gt;

&lt;p&gt;To make sure we don't commit to the same errors as we did in the past such as encouraging innovation in potentially ethically discussable directions, I think it's our role, as more senior developers, mentors, and older adults &lt;strong&gt;to sensitize youngers and to educate them to reduce this kind of problems in the future, making them "exceptions" and not the norm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And hopefully, we should educate ourselves, too, because, you know, it's not the fault of the others.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How do I choose which SSR strategy to adopt?</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Tue, 26 May 2020 13:27:18 +0000</pubDate>
      <link>https://forem.com/mfrachet/how-do-i-choose-which-ssr-strategy-to-adopt-1ki4</link>
      <guid>https://forem.com/mfrachet/how-do-i-choose-which-ssr-strategy-to-adopt-1ki4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is crossed posted on my personal blog: &lt;a href="https://mfrachet.github.io/how-do-i-choose-a-ssr-strategy"&gt;https://mfrachet.github.io/how-do-i-choose-a-ssr-strategy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Also, this post is opinionated and based on my personal experience. It's not a source of truth, just the way I approach SSR on my daily job.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Server Side Rendering (or SSR) is a big trend. In the React ecosystem, we have plenty of tools that rely on it such as &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsbyjs&lt;/a&gt; or &lt;a href="https://nextjs.org/"&gt;Nextjs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before getting further, let's see what happens when a user makes a request on a site that is not built using SSR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The browser makes a request on a specific endpoint&lt;/li&gt;
&lt;li&gt;It downloads an empty HTML file that only owns a bunch of &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags to load some JavaScript code&lt;/li&gt;
&lt;li&gt;It resolves / parses / compiles the JavaScript code&lt;/li&gt;
&lt;li&gt;It executes the JavaScript code and only then the application can display the content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how the good old &lt;a href="https://angularjs.org/"&gt;Angularjs&lt;/a&gt; or &lt;a href="https://jquery.com/"&gt;JQuery&lt;/a&gt; applications were working. And this is also what happens when we use &lt;a href="https://github.com/facebook/create-react-app"&gt;create-react-app&lt;/a&gt;.&lt;br&gt;
We say that these applications rely on "Client Side Rendering" (or CSR).&lt;/p&gt;
&lt;h4&gt;
  
  
  Why SSR has been invented?
&lt;/h4&gt;

&lt;p&gt;When building an application using CSR, we &lt;strong&gt;always&lt;/strong&gt; have to wait for the JavaScript code to be resolved / parsed / compiled / executed &lt;strong&gt;before&lt;/strong&gt; displaying anything on the screen.&lt;br&gt;
The JavaScript application is responsible for filling the HTML file dynamically in the browser.&lt;br&gt;
And this can be problematic because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSR applications are not optimized for SEO (&lt;a href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web#seo"&gt;SEO works, but it's a bit more complicated&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;We don't benefit from a good media sharing experience&lt;/li&gt;
&lt;li&gt;Displaying the first meaningful content or wait for the application to be interactive can take time when the application is big&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I remember having worked on Angularjs applications back in 2013 where it could take around 10 seconds to display the first content on the page.&lt;/p&gt;
&lt;h4&gt;
  
  
  How does it solve these problems?
&lt;/h4&gt;

&lt;p&gt;The main idea behind SSR is to generate HTML content and display it to the user the sooner. HTML is easy to understand for browsers, they know how to execute it really fast.&lt;/p&gt;

&lt;p&gt;This way, when a user navigates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The browser makes a request on a specific endpoint&lt;/li&gt;
&lt;li&gt;It downloads &lt;strong&gt;an already filled HTML content&lt;/strong&gt; and can already display it to the user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which is good enough to solve the 3 problems we had:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- CSR applications are not optimized for SEO
+ HTML is optimized for SEO

- We don't benefit from a good media sharing experience
+ Pre-filled HTML owns the necessary meta to have a good sharing experience

- Displaying the first meaningful content or wait for the application to be interactive can take time
+ Displaying HTML content is probably one of the fastest thing a browser can do
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the most basic idea behind the term SSR and with this in mind, we can create complex and powerful mechanisms (non-exhaustive list):&lt;/p&gt;

&lt;h5&gt;
  
  
  Runtime SSR
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Start a NodeJS server&lt;/li&gt;
&lt;li&gt;When a request is made, render static HTML content (string format)&lt;/li&gt;
&lt;li&gt;When the browser is ready, start a client side application for interactivity&lt;/li&gt;
&lt;li&gt;Tools: &lt;a href="https://nextjs.org/"&gt;Nextjs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first way to rely on SSR we've seen in the React community. Can be complex to put in practice and costs money: &lt;br&gt;
one or several NodeJS servers have to be running in production to manage the requests.&lt;/p&gt;

&lt;h5&gt;
  
  
  Static Generation
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;At build time (when running &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;yarn build&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Generate as many &lt;strong&gt;HTML files (.html)&lt;/strong&gt; as necessary&lt;/li&gt;
&lt;li&gt;When a request is made, render the associated .html file&lt;/li&gt;
&lt;li&gt;Tools: &lt;a href="https://docusaurus.io/"&gt;Docusaurus&lt;/a&gt;, &lt;a href="https://github.com/11ty/eleventy/"&gt;11ty&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Performance case study by &lt;a href="https://medium.com/dev-channel/a-netflix-web-performance-case-study-c0bcde26a9d9"&gt;Netflix on the landing page&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common in the documentation / blogging area where interactivity is not required. Tools take something like Markdown content in input and create&lt;br&gt;
the associated .html files as output. Not too complex to use in practice, not expensive thanks to CDN hostings. &lt;/p&gt;

&lt;h5&gt;
  
  
  Build time SSR / Pre-rendering
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;At build time (when running &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;yarn build&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Generate as many &lt;strong&gt;HTML files (.html)&lt;/strong&gt; as necessary&lt;/li&gt;
&lt;li&gt;When a request is made, render the associated .html file&lt;/li&gt;
&lt;li&gt;When the browser is ready, start a client side application for interactivity&lt;/li&gt;
&lt;li&gt;Tools: &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt;, &lt;a href="https://nextjs.org/"&gt;Nextjs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probably my favorite of all the listed solutions. Very scalable, highly interactive, not too complex to use in practice and not expensive thanks to CDN hostings. &lt;/p&gt;

&lt;h4&gt;
  
  
  How to choose?
&lt;/h4&gt;

&lt;p&gt;This is where it gets tricky.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choosing a strategy is not about finding the best solution&lt;/strong&gt;. It's about evaluating trade offs and taking the&lt;br&gt;
technic that provides &lt;strong&gt;the most benefit in our context&lt;/strong&gt; than it provides drawbacks.&lt;/p&gt;

&lt;p&gt;Also, I'm feeling that the last few years we tend to use SSR almost everywhere and as much as we can.&lt;br&gt;
While it's an amazing tool that helps in many situations, I think&lt;br&gt;
we should keep in mind that &lt;strong&gt;it's just a tool&lt;/strong&gt; - not a silver bullet solution. If we don't face the problems it's supposed to solve, I'm not convinced we should introduce it in a project.&lt;br&gt;
&lt;strong&gt;Remember that introducing SSR is not free&lt;/strong&gt;, it has a technical cost and a potential infrastructure cost.&lt;/p&gt;

&lt;p&gt;Finally we don't have to choose a single way of building an app: we can cross the ideas and create a system that provides the best user experience in our scenario.&lt;/p&gt;

&lt;p&gt;The following diagram is one of the mental representations I'm using to determine when I would consider using a technic over another one in a given situation. &lt;strong&gt;It's not a source of truth at all&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3_UM5m6j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mfrachet.github.io/static/dc4089078ea1f5573fa5a69ed965fcee/88b03/ssr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3_UM5m6j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mfrachet.github.io/static/dc4089078ea1f5573fa5a69ed965fcee/88b03/ssr.png" alt="Mental SSR path to make a choice"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A tale of bounded components</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Wed, 31 Jul 2019 18:18:02 +0000</pubDate>
      <link>https://forem.com/mfrachet/a-tale-of-bounded-components-4af2</link>
      <guid>https://forem.com/mfrachet/a-tale-of-bounded-components-4af2</guid>
      <description>&lt;p&gt;Building reusable UI components is hard. I always rely on an iterative approach and write my component 2-3 times before getting something that I find useful and reusable across my applications. It's kind of a game to find the "good" abstraction and the "good" way to create them.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://acodingdance.io/a-note-on-composing-components-with-react/"&gt;A note on composing components with React&lt;/a&gt;, I've briefly talked about my conception of composition by taking the example of &lt;a href="https://material.io/design/components/cards.html"&gt;Google Material Design Cards&lt;/a&gt; and how I would have implemented such a thing. This post is an extension of the previous one so I recommend you take a look ☺️.&lt;/p&gt;

&lt;p&gt;Today I want to share with you my experience while implementing a UI component library based on a design system and how my team and I have managed to build a &lt;em&gt;bit more complex components&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's talk about components that &lt;em&gt;share something&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Radio &lt;em&gt;buttons&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;I'm going to take the example of radio buttons and this for two reasons.&lt;/p&gt;

&lt;p&gt;The first one is that I'm building the UI component library with &lt;a href="https://facebook.github.io/react-native/"&gt;React Native&lt;/a&gt; and that it doesn't provide a built-in Radio component and the second one is because radio buttons are kind of &lt;em&gt;special&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;By definition, it's a group of selectable elements where only one element can be selected at a time. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio"&gt;Here's a quick link to the MDN definition of &lt;strong&gt;radio&lt;/strong&gt; and &lt;strong&gt;radio groups&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In HTML this link is represented by the &lt;code&gt;input&lt;/code&gt; &lt;code&gt;name&lt;/code&gt; attribute:&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="c1"&gt;// this is from MDN&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contact"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&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;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contact"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"phone"&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;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contact"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think that we can call these &lt;strong&gt;compound semantic elements&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If we want to build &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; components that matches the previous definition of radio elements, these components have to share some information with some other ones.&lt;/p&gt;

&lt;p&gt;In the React world, we can say that these components &lt;strong&gt;are sharing some state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To manage this kind of shared state, we can rely on different approaches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Through the parent state
&lt;/h3&gt;

&lt;p&gt;The simplest thing to do in a React world is to rely on the parent component state.&lt;/p&gt;

&lt;p&gt;Let's imagine the following snippet:&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;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedRadio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectRadio&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Radio&lt;/span&gt; &lt;span class="na"&gt;onPress&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;selectRadio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedRadio&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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;Radio&lt;/span&gt; &lt;span class="na"&gt;onPress&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;selectRadio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedRadio&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&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;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;The selected value is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedRadio&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;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&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;This is a &lt;em&gt;fine&lt;/em&gt; approach and it works as long as we accept to manage the state of the &lt;code&gt;&amp;lt;Radio /&amp;gt;&lt;/code&gt; components in every of their parents.&lt;/p&gt;

&lt;p&gt;However, in this code, there is something that we lost: &lt;strong&gt;the linked nature of radio buttons&lt;/strong&gt;. Or at least the &lt;em&gt;family&lt;/em&gt; link of the radio elements.&lt;/p&gt;

&lt;p&gt;Of course the selected value will be reflected thanks to the parent state. But the radio group is dependent on the parent and not only on itself. On the web platform for example, there are no parent to manage the link between the elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a global state management tool (let's say Redux)
&lt;/h3&gt;

&lt;p&gt;We can also rely on a global state management tool that will store the actual selected value and provide it across the app:&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;mapStateToProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownProps&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="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedRadio&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapDispatchToProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;selectMe&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="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT_RADIO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;newSelectedRadio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RadioEnhanced&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapStateToProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapDispatchToProps&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;Radio&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;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;selectedRadio&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RadioEnhanced&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;RadioEnhanced&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;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;The selected value is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedRadio&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;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also a &lt;em&gt;fine&lt;/em&gt; approach and it has the benefit of keeping the linked nature of the Radio element using the global state.&lt;/p&gt;

&lt;p&gt;However, we have to define a new Redux key in the store for every different kind of Radio component. We also have to create a reducer for each kind of Radio groups and so forth. And this will be the same even if you don't use Redux but an other global state management system.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://reactjs.org/docs/context.html"&gt;React's context API&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;I often hear that using the React context is a bad practice. I don't totally agree with this statement. I think that we have to understand when not to use it and to use it sparsely. The context is a feature that is built in in React, so they may probably be some good use-cases for it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What I suggest before writing any component implementation is to imagine your ideal way to use that component. I often start by writing the shape I want it to have (its API), let's say:&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;MyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RadioGroup&lt;/span&gt; &lt;span class="na"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSelected&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;Radio&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"first"&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;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My first radio&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&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;Radio&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;Radio&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"second"&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;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My second radio&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&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;Radio&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;RadioGroup&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;I like this kind of API because it's straightforward to read.&lt;/p&gt;

&lt;p&gt;This code represents a group of radio components that act together. When the &lt;code&gt;&amp;lt;Radio name="first" /&amp;gt;&lt;/code&gt; is selected, every other radio components in the &lt;code&gt;RadioGroup&lt;/code&gt; children tree will be unselected.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;selected&lt;/code&gt; prop of the &lt;code&gt;RadioGroup&lt;/code&gt; component corresponds to the &lt;code&gt;name&lt;/code&gt; of the selected radio component. If I want to select the &lt;code&gt;first&lt;/code&gt; radio then the code will look like &lt;code&gt;&amp;lt;RadioGroup selected="first"&amp;gt;...&amp;lt;/RadioGroup&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can create this behavior and feeling of link using &lt;a href="https://reactjs.org/docs/context.html"&gt;React's context API&lt;/a&gt; where the &lt;code&gt;RadioGroup&lt;/code&gt; component owns the actual selected &lt;code&gt;name&lt;/code&gt; in its context and share it across its different &lt;code&gt;Radio&lt;/code&gt; children.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This technique of &lt;em&gt;hiding&lt;/em&gt; the state management between components is called &lt;em&gt;implicit state passing&lt;/em&gt;&lt;/strong&gt;. We manage the state in a way the developer doesn't have to care about and does not have to implement multiple times.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/elastic-surf-pxxdt"&gt;Here's a running codesandbox of the &lt;code&gt;Radio&lt;/code&gt; and &lt;code&gt;RadioGroup&lt;/code&gt; implementation&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;We now have a good understanding of the &lt;code&gt;React context&lt;/code&gt; API. Let's explore another advanced function of React that also allows to pass some implicit states through another example: the &lt;code&gt;Tabs&lt;/code&gt; one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;Tabs&lt;/code&gt; example
&lt;/h2&gt;

&lt;p&gt;In my posts, I'm talking a lot about the Tabs example that &lt;a href="https://twitter.com/ryanflorence"&gt;Ryan Florence&lt;/a&gt; has provided in &lt;a href="https://www.youtube.com/watch?v=hEGg-3pIHlE"&gt;this video&lt;/a&gt;. It's this video that made me realise that I was doing some things wrong and that I had to understand the "composition" concept.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Tabs&lt;/code&gt; are UI elements that define (UI) interfaces sharing a visual link. They have to be close to each other to provide a good user experience. It doesn't make sense to create a tab at the top left side of the device with another one at the bottom right side.&lt;/p&gt;

&lt;p&gt;I like to put &lt;code&gt;Tabs&lt;/code&gt; in the category of layout components: they are not really business oriented nor atomic UI components. They represent a way to display information and how to navigate between different types of information.&lt;/p&gt;

&lt;p&gt;We can imagine this components using multiple approaches and one that often comes and that I used to work with was the data driven approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Driven approach
&lt;/h3&gt;

&lt;p&gt;A data driven approach is a way to build components so that a component requires its props to have a specific shape to be used. For example:&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;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;Component&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="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;First&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Second&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;Component&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="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;Second&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Tabs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;SelectedComponent&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;SelectedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selected&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="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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;black&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;SelectedComponent&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SelectedComponent&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;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// would be used &amp;lt;Tabs item={items} /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;Tabs&lt;/code&gt; component knows the shape of each of its item to be able to display them correctly. It's a contract between the object and the component.&lt;/p&gt;

&lt;p&gt;While it's okay to work using this approach, I think that it's good to think of a way to avoid this kind of tight coupling. Composition can help to achieve this.&lt;/p&gt;

&lt;p&gt;As I have mentioned before, let's image our perfect world API. Something like the following one looks great to me:&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="nc"&gt;Tabs&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;TabsHeader&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;TabHead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;First button&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TabHead&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;TabHead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Second button&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TabHead&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;TabsHeader&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;TabsBody&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;Tab&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;FirstComponent&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;Tab&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;Tab&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;SecondComponent&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;Tab&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;TabsBody&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;Tabs&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using React, how can we create the different &lt;code&gt;TabXXX&lt;/code&gt; component so that it works this way?&lt;/p&gt;

&lt;p&gt;We could have done this using the context API, but for now, I want to introduce the &lt;code&gt;React.cloneElement&lt;/code&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  React.cloneElement
&lt;/h3&gt;

&lt;p&gt;This function allows to clone a React element with its actual props with the possibility to override them or to add new ones.&lt;/p&gt;

&lt;p&gt;It can be used as following:&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;element&lt;/span&gt; &lt;span class="o"&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;Hello world&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clone&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="nx"&gt;cloneElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&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;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use this definition of the &lt;code&gt;React.cloneElement&lt;/code&gt; function to provide some props to the children of a component, implicitly.&lt;/p&gt;

&lt;p&gt;For example, we will add a props to the &lt;code&gt;TabHead&lt;/code&gt; components so that they become clickable.&lt;br&gt;
We will also add a &lt;code&gt;selectIndex&lt;/code&gt; prop to the &lt;code&gt;TabsBody&lt;/code&gt; component so that he knows which component has to be displayed or not.&lt;/p&gt;
&lt;h4&gt;
  
  
  Implementing the &lt;code&gt;Tabs&lt;/code&gt; component
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;Tabs&lt;/code&gt; component is the owner, the one that knows everything. It owns the actual selected index and knows how to modify that selected index:&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;Tabs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;selectIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;setSelectedIndex&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;In this case &lt;code&gt;React.cloneElement&lt;/code&gt; enhances the child component by adding them two props: the actual selected index and a way to modify that selected index.&lt;/p&gt;

&lt;p&gt;In fact, we'll pass down these two props respectively to the &lt;code&gt;TabHead&lt;/code&gt;s and the &lt;code&gt;Tab&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TabsHeader&lt;/code&gt; component will receive the &lt;code&gt;selectIndex&lt;/code&gt; function and will pass it down to its &lt;code&gt;TabHead&lt;/code&gt; children with a subtle variant: we'll scope the actual index of the &lt;code&gt;TabHead&lt;/code&gt; component so that they can call the &lt;code&gt;selectIndex&lt;/code&gt; function without passing their index explicitly:&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;TabsHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;selectIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;selectIndex&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="nx"&gt;selectIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TabHead&lt;/code&gt; will simply look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TabHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;selectIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectIndex&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;TabsBody&lt;/code&gt; role is to display only the element that matches the selected index. This can be achieved using &lt;code&gt;Array.prototype.find&lt;/code&gt; on the children:&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;TabsBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codesandbox.io/s/hardcore-thompson-ibxow"&gt;Here's a link to a codesandbox of the previous snippets.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I suggest you take some times to analyse and get familiar with this kind of code. It's something that I wasn't used to before diving into it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;So there we are, these are examples with some explanations of more complex and linked components!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How is the React lazy function implemented? Suspense... It gonna be short 😉</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Tue, 30 Jul 2019 19:20:58 +0000</pubDate>
      <link>https://forem.com/mfrachet/how-is-the-react-lazy-function-implemented-suspense-it-gonna-be-short-4pkn</link>
      <guid>https://forem.com/mfrachet/how-is-the-react-lazy-function-implemented-suspense-it-gonna-be-short-4pkn</guid>
      <description>&lt;p&gt;It's been a time since the React's team has introduced Suspense and concurrent rendering. With hooks, it's the new amazing feature that React is providing.&lt;/p&gt;

&lt;p&gt;We are "able" (at least in dev-mode) to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create applications that manage specific priorities over our asynchronous operations&lt;/li&gt;
&lt;li&gt;manage asynchronous computations just like if they were synchronous&lt;/li&gt;
&lt;li&gt;use functional components everywhere instead of classes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm really excited about the future of React!&lt;/p&gt;




&lt;p&gt;And today, I wanted to talk about a &lt;code&gt;Suspense&lt;/code&gt; specific feature which is the &lt;code&gt;lazy&lt;/code&gt; function that was introduced in &lt;a href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html"&gt;React v16.6&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This function aims to provide a simple way to rely on bundler's code splitting using some code like:&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;lazy&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="err"&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;LazyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;./components/myComponent&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;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;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;Waiting...&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;LazyComponent&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;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What the?..
&lt;/h2&gt;

&lt;p&gt;It can be a bit disturbing at first, how can we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code split our code, which is a build time feature&lt;/li&gt;
&lt;li&gt;make an asychronous computation that creates a component&lt;/li&gt;
&lt;li&gt;use an (async?) component in a render function which aims to be synchronous&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;using 2-3 lines?...!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Suspense...🤯
&lt;/h2&gt;

&lt;p&gt;This is not &lt;em&gt;that&lt;/em&gt; magic and can exist thanks to the &lt;code&gt;Suspense&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;This component is a bit special and whenever you will &lt;code&gt;throw&lt;/code&gt; a &lt;code&gt;Promise&lt;/code&gt; in one of its children, it will &lt;code&gt;catch&lt;/code&gt; that promise, resolve it and re-render its children.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did you know that you were able to throw something else than errors in JavaScript?!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is why it's called &lt;code&gt;Suspense&lt;/code&gt;: it &lt;em&gt;suspends&lt;/em&gt; the normal execution flow of your application thanks to the &lt;code&gt;throw&lt;/code&gt; keyword, and make some specific computations before "resuming" it. It doesn't resume it at the exact position of your code, but at least, it re-renders its children &lt;strong&gt;which make you feel like you were getting back to the old execution position&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I tried to write about it in &lt;a href="https://medium.com/free-code-camp/react-cache-time-slicing-and-fetching-with-a-synchronous-api-2a57dc9c2e6d"&gt;this Medium post&lt;/a&gt; but without success - my thoughts at that period were not that organised.&lt;/p&gt;

&lt;p&gt;I won't keep the "suspense" for now, so let's check &lt;em&gt;one&lt;/em&gt; implementation of the &lt;code&gt;lazy&lt;/code&gt; function I've came across:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;IDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;loaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;modulePathResolver&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;IDS&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LoadedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LoadedComponent&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadedComponent&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;modulePathResolver&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lazyModule&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lazyModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;a href="https://gist.github.com/mfrachet/a04cc57a500de85170e2ade4b9406305"&gt;It's available on github gist if you want to play with it.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obviously, this snippet only works if the component is used inside a &lt;code&gt;Suspense&lt;/code&gt; parent.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;lazy&lt;/code&gt; function accepts one argument &lt;code&gt;modulePathResolver&lt;/code&gt; which is a &lt;code&gt;Promise&lt;/code&gt; that resolved the module containing your &lt;em&gt;lazy&lt;/em&gt; component.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;lazy&lt;/code&gt; function returns a function which is in fact a (functional) component. All the references to &lt;code&gt;id&lt;/code&gt; exist only to make sure that the component has only loaded once.&lt;/p&gt;

&lt;p&gt;If you take a closer look at the code, it really looks like a cache system, but instead of setting the cached value directly, it &lt;code&gt;throw&lt;/code&gt;s a promise that wraps the cache setting so that the Suspense parent can resolve it, &lt;em&gt;lazily&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And you know what? Since it's an asynchronous operation, it can take some time to execute, milliseconds, seconds or even minutes. And what is displayed &lt;em&gt;during&lt;/em&gt; the asynchronous resolution? The &lt;code&gt;fallback&lt;/code&gt; prop of the &lt;code&gt;Suspense&lt;/code&gt; component is displayed! Nothing more!&lt;/p&gt;

&lt;h2&gt;
  
  
  And now, what?
&lt;/h2&gt;

&lt;p&gt;You have an idea of the way the &lt;code&gt;lazy&lt;/code&gt; function is working but you also now know how &lt;code&gt;Suspense&lt;/code&gt; is working. You can now imagine every kind of asynchronous resolution without creating &lt;code&gt;isLoading&lt;/code&gt; states everywhere, every-time. What about lazy image loading with low-high quality pictures 😉?&lt;/p&gt;

&lt;p&gt;Jared Palmer is really good advocate of this and has talked about it in multiple talks he has given like the one at &lt;a href="https://www.youtube.com/watch?v=u_0ZMiQZr0k"&gt;Chain React 2019&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My point on this feature is that it also pushes the side effect computations we use to make to the edge of our applications. We can make asynchronous stuff using synchronous APIs without headaches. It makes me think of monads and the capability to isolate and compose what causes (side) effects with trivial code.&lt;/p&gt;

&lt;p&gt;Isn't this pretty cool?!&lt;/p&gt;

&lt;p&gt;Happy coding everyone! React has some beautiful days to come! 🚀&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Understanding the React Native bridge concept</title>
      <dc:creator>Marvin</dc:creator>
      <pubDate>Fri, 28 Jun 2019 12:04:56 +0000</pubDate>
      <link>https://forem.com/mfrachet/understanding-the-react-native-bridge-concept-1k90</link>
      <guid>https://forem.com/mfrachet/understanding-the-react-native-bridge-concept-1k90</guid>
      <description>&lt;p&gt;And why its architecture is awesome, at a top level.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;&lt;a href="https://hackernoon.com/understanding-react-native-bridge-concept-e9526066ddb8" rel="noopener noreferrer"&gt;Originally posted on @medium&lt;/a&gt;&lt;/em&gt; and &lt;a href="https://acodingdance.io/understanding-the-react-native-bridge-concept/" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://acodingdance.io/tasting-the-future-the-new-react-native-architecture/" rel="noopener noreferrer"&gt;Here’s a post concerning the new (future) react-native architecture&lt;/a&gt;&lt;/em&gt;&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%2Facodingdance.io%2Fassets%2Frn.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%2Facodingdance.io%2Fassets%2Frn.png" alt="React Native"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React Native is often presented as a game changer that allows to run JavaScript code inside a mobile environment. Its main strength is that it doesn’t rely on &lt;a href="https://www.telerik.com/platform-next-level" rel="noopener noreferrer"&gt;webviews&lt;/a&gt; like other competitors (&lt;a href="https://phonegap.com/" rel="noopener noreferrer"&gt;Phonegap&lt;/a&gt;, &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic&lt;/a&gt;, &lt;a href="https://cordova.apache.org/" rel="noopener noreferrer"&gt;Cordova&lt;/a&gt;…, but on the actual real materials provided by the different platforms. It has built-in access to all the native views and components, and to about 70 specific device APIs by default (&lt;a href="https://facebook.github.io/react-native/docs/native-modules-ios.html" rel="noopener noreferrer"&gt;you can extend it&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;When writing React Native apps, we build native UIs. And that’s the key point, we create UIView instances just like we would have with platform specific languages:&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%2Facodingdance.io%2Fassets%2Fxcode.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%2Facodingdance.io%2Fassets%2Fxcode.png" alt="RCTView implements UIView"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first assumption on this framework was something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They probably create an AST from the JS code and transform it to make it run on multiple devices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That would make sense and that’s actually what &lt;a href="https://docs.google.com/presentation/d/1cw7A4HbvM_Abv320rVgPVGiUP2msVs7tfGbkgdrTy0I/edit#slide=id.p" rel="noopener noreferrer"&gt;Google/Flutter&lt;/a&gt; does while building apps (with &lt;a href="https://www.dartlang.org/" rel="noopener noreferrer"&gt;Dartlang&lt;/a&gt;). But that’s not the React Native way.&lt;/p&gt;

&lt;p&gt;The main problem with this approach is that targeting platforms for compilation based on JavaScript code would imply the creation of new compilers. I don’t know any existing tool accepting JavaScript as entry code that is able to produce code for every targeted platform (eventually see &lt;a href="https://jasonette.com/" rel="noopener noreferrer"&gt;Jasonette&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%2Facodingdance.io%2Fassets%2Fcompiler.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%2Facodingdance.io%2Fassets%2Fcompiler.png" alt="NB: some have tried but only for mobile development with opinionated approaches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what currently exist are compilers that target their own specific platform. For example, we have compilers that accept Java / Kotlin code and target Android platform, or Obj-C / Swift targeting iOS platform. It exists many compilers for different languages and targets. They do their job well because &lt;strong&gt;they have been designed&lt;/strong&gt; to create optimised artefacts for them.&lt;/p&gt;

&lt;p&gt;React Native is built in such a way that &lt;strong&gt;it uses existing compilers&lt;/strong&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%2Facodingdance.io%2Fassets%2Fcross-compiler.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%2Facodingdance.io%2Fassets%2Fcross-compiler.png" alt="NB: some have tried but only for mobile development with opinionated approaches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s built with a really opened architecture that allows the code to be run, not only on mobile devices, but also on other platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kusti8/proton-native" rel="noopener noreferrer"&gt;Desktop applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://facebook.github.io/react-360/" rel="noopener noreferrer"&gt;Virtual Reality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=16198843" rel="noopener noreferrer"&gt;Many more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can also be used with other frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/alibaba/weex" rel="noopener noreferrer"&gt;Weex&lt;/a&gt;, a React Native port of Vuejs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/react-native-renderer" rel="noopener noreferrer"&gt;a custom Angular renderer that allows to run ng apps in devices, with React Native&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how did the team build such a framework, that is platform and framework agnostic, by using the existing tools &amp;amp; compilers?&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple realms interacting, nothing else
&lt;/h2&gt;

&lt;p&gt;Let’s take a step back and look at the big picture of React Native.&lt;/p&gt;

&lt;p&gt;React Native deals with two realms, the JavaScript one and the Native one. Both of them are able to share information. They communicate using a “bridge”, which is definitely the very heart of the React Native architecture, the part that offers so much flexibility.&lt;/p&gt;

&lt;p&gt;The bridge is the concept that provides a way for bidirectional and asynchronous communications between these two universes. What’s important here is that they are completely written in different technologies, but &lt;strong&gt;they are able to communicate&lt;/strong&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%2Facodingdance.io%2Fassets%2Fdistributed.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%2Facodingdance.io%2Fassets%2Fdistributed.png" alt="JS threads communicates with the native ones through the bridge"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Remember your backend side
&lt;/h2&gt;

&lt;p&gt;Let’s remember when we were coding distributed backend applications with multi-service communications.&lt;/p&gt;

&lt;p&gt;How do we manage communication between two services that are completely different at a language/platform level ?&lt;/p&gt;

&lt;p&gt;We used interoperable languages, such as JSON or XML, and we relied on asynchronous protocols such as &lt;a href="https://www.amqp.org/about/what" rel="noopener noreferrer"&gt;AMQP&lt;/a&gt; (or any other like &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Kafka&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%2Facodingdance.io%2Fassets%2Fbroker.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%2Facodingdance.io%2Fassets%2Fbroker.png" alt="Bidirectional communications between heterogeneous services"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we want these two services to communicate, we rely on a message queue. The first service pushes some commands inside the queue and the other one has to execute these commands when possible.&lt;/p&gt;

&lt;p&gt;React Native behaves the same way. The JavaScript realm sends asynchronous JSON messages describing the action the Native part is supposed to accomplish.&lt;/p&gt;

&lt;p&gt;For example, the JavaScript side will send information concerning &lt;strong&gt;the views that must be created by the Native side&lt;/strong&gt;. When the Native side is ready, it will effectively create the views:&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%2Facodingdance.io%2Fassets%2Fbridge.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%2Facodingdance.io%2Fassets%2Fbridge.png" alt="JavaScript sends commands asynchronously to the Native side for view management, with JSON"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In React Native, the bridge endorses the message broker role, handling asynchronous commands between the two different worlds.&lt;/p&gt;

&lt;p&gt;It offers multiple possibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;since it’s asynchronous, it’s non blocking, and therefore allows for smooth view management on the screen (~6O fps is the React Native golden goal)&lt;/li&gt;
&lt;li&gt;since it’s decoupled and based on interoperable languages, it’s wide open to other frameworks and rendering systems &lt;strong&gt;provided that they respect the React Native bridge command interface&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more the bridge’s language is ubiquitous and universal, the more the possibilities are… and it is indeed!&lt;/p&gt;

&lt;h2&gt;
  
  
  The bridge implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/facebook/react-native/blob/81860c59c3453429bb4e70da2c372c92e66e134c/ReactCommon/cxxreact/NativeToJsBridge.cpp#L29" rel="noopener noreferrer"&gt;The bridge is built in C/C++ and thus, can be run on multiple platforms, OS etc...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It embeds the &lt;a href="https://developer.apple.com/documentation/javascriptcore" rel="noopener noreferrer"&gt;Apple JavaScriptCore framework&lt;/a&gt; in, which exposes APIs to access the actual JavacriptCore VM capabilities. Many people use these APIs on the Obj-C and Swift world. But there is a C API, and the Obj-C one is actually just a wrapper.&lt;/p&gt;

&lt;p&gt;With this in mind, JavaScript code can be run inside a C/C++ program. It can inject variables, functions and declare globals to enhance the JavaScript existing code. React Native relies on this kind of magic to make JavaScript communicate with the native world and thus &lt;a href="https://github.com/facebook/react-native/blob/52f431b4bb29062abd8ce20e01a4e60b47151a80/Libraries/BatchedBridge/MessageQueue.js#L254" rel="noopener noreferrer"&gt;trigger actions in the C/C++ world&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Injecting stuff inside the JavaScript code also means that functions can be executed by the C/C++ code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This diagram quickly sums up how the JavaScript world is able to deal with the C/C++ 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%2Facodingdance.io%2Fassets%2Fjs-side.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%2Facodingdance.io%2Fassets%2Fjs-side.png" alt="The JS code is managed by the JSCore framework"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The native side
&lt;/h2&gt;

&lt;p&gt;The communication on the native side is “the easiest” part.&lt;/p&gt;

&lt;p&gt;Let’s begin with the iOS platform. Since Obj-C is an extension of the C language, it can communicate with it natively. This way, exchanges between the bridge and the Swift / Obj-C world are easy and natural.&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%2Facodingdance.io%2Fassets%2Fios.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%2Facodingdance.io%2Fassets%2Fios.png" alt="High level diagram of JS interacting with iOS world"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Android, we need to rely on the &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jni/" rel="noopener noreferrer"&gt;Java Native Interface&lt;/a&gt; to dialog with the bridge.&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%2Facodingdance.io%2Fassets%2Fandroid.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%2Facodingdance.io%2Fassets%2Fandroid.png" alt="High level diagram of JS interacting with Android world"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s an old but really awesome and deep post explaining &lt;a href="https://tadeuzagallo.com/blog/react-native-bridge/" rel="noopener noreferrer"&gt;how the bridge is implemented on iOS by Tadeu Zagallo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me know if you have further questions regarding React Native internals. I’ll try to provide all that I know on the topic.&lt;/p&gt;

&lt;p&gt;Thanks to my mates &lt;a href="https://medium.com/@ZenikaIT" rel="noopener noreferrer"&gt;@Zenika&lt;/a&gt; and &lt;a href="https://tech.m6web.fr/" rel="noopener noreferrer"&gt;@M6Web&lt;/a&gt; for the reviews!&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
