<?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: x0s3</title>
    <description>The latest articles on Forem by x0s3 (@x0s3).</description>
    <link>https://forem.com/x0s3</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%2F153521%2Fcc017314-1ef1-40d9-be71-65e226ed6f6c.jpeg</url>
      <title>Forem: x0s3</title>
      <link>https://forem.com/x0s3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/x0s3"/>
    <language>en</language>
    <item>
      <title>Implementando un API Client Generator con Proxies de JavaScript y TypeScript Overloads</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Tue, 07 Apr 2026 18:30:10 +0000</pubDate>
      <link>https://forem.com/x0s3/implementando-un-api-client-generator-con-proxies-de-javascript-y-typescript-overloads-2chf</link>
      <guid>https://forem.com/x0s3/implementando-un-api-client-generator-con-proxies-de-javascript-y-typescript-overloads-2chf</guid>
      <description>&lt;h2&gt;
  
  
  Generador de clientes: Centralizando el consumo de APIs con Proxies y TypeScript
&lt;/h2&gt;

&lt;p&gt;Si estás trabajando en un ecosistema de microservicios, probablemente estés harto de configurar instancias de Axios/Ky en cada rincón de tu proyecto. El boilerplate se acumula, el tipado se vuelve inconsistente y mantener las configuraciones base (como headers de tracking o transformación de cases) se vuelve una pesadilla.&lt;/p&gt;

&lt;p&gt;Hoy quiero mostrarte cómo pasar de un desorden de configuraciones a una &lt;strong&gt;interfaz limpia y centralizada&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Esto es lo que queremos evitar ❌&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&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;url&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;SERVICE1&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;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/user-data`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  La API Final: Así es como debería verse tu código
&lt;/h2&gt;

&lt;p&gt;Imagina que en lugar de importar configuraciones pesadas, simplemente defines tus servicios y ya tienes clientes listos para usar:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;clientGenerator&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;./api-utils&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;connector&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;./base-connector&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Definimos y generamos&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;service1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;service2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;clientGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;service1&lt;/span&gt;&lt;span class="p"&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;SERVICE1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;service2&lt;/span&gt;&lt;span class="p"&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;SERVICE2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Usamos con tipado automático&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;service1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;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;/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// 'data' es MyResponse directamente.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Necesitas la respuesta completa? Solo pasas un flag y el tipado cambia mágicamente:&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="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;service1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;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;/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;resolveWithFullResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt; 

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 200&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Tipado&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="nx"&gt;MyResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Tipado&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ¿Cómo llegamos a esto? La magia por dentro
&lt;/h2&gt;

&lt;p&gt;Para lograr esta sintaxis tan limpia sin repetir código para cada método HTTP (&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;...), usamos dos herramientas poderosas: &lt;strong&gt;Proxies de JavaScript&lt;/strong&gt; y &lt;strong&gt;Sobrecarga de funciones en TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. El Proxy como "Atrapa-todo"
&lt;/h3&gt;

&lt;p&gt;En lugar de definir un objeto con métodos manuales, usamos un &lt;code&gt;Proxy&lt;/code&gt;. Este intercepta cualquier propiedad que intentes acceder (como &lt;code&gt;.get&lt;/code&gt; o &lt;code&gt;.post&lt;/code&gt;) y la convierte dinámicamente en una llamada al conector.&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="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Connector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;new&lt;/span&gt; &lt;span class="nb"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Client&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;as&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTTPMethod&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="na"&gt;requestMethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ClientMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;endpoint&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="kr"&gt;string&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="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ClientRequestConfig&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="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;requestBase&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="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;endpoint&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;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;// Casting to `any` so that the type inference works correctly :D&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;connector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TResponse&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;requestBase&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&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="nx"&gt;requestMethod&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;Esto hace que nuestro cliente sea virtualmente infinito y extremadamente ligero. No importa si mañana el conector soporta un nuevo verbo HTTP; el Proxy simplemente lo capturará.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Tipado inteligente (Function Overloads)
&lt;/h3&gt;

&lt;p&gt;Uno de los retos era que, a veces, queremos solo la &lt;code&gt;data&lt;/code&gt; y otras veces el &lt;code&gt;AxiosResponse&lt;/code&gt; completo. Para que TypeScript no nos dé errores ni use &lt;code&gt;any&lt;/code&gt;, aplicamos &lt;strong&gt;sobrecarga de tipos&lt;/strong&gt;:&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;type&lt;/span&gt; &lt;span class="nx"&gt;ClientMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Sobrecarga 1: Si no pides la respuesta completa, devuelve TResponse&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;endpoint&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="kr"&gt;string&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="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ClientRequestConfigNormal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&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;TResponse&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;// Sobrecarga 2: Si resolveWithFullResponse es true, devuelve AxiosResponse&amp;lt;TResponse&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;endpoint&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="kr"&gt;string&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="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ClientRequestConfigFullResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&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;AxiosResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Esto es lo que permite que el IDE sea "inteligente" y sepa exactamente qué tipo de objeto tienes entre manos según las opciones que envíes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. La Factoría: &lt;code&gt;clientGenerator&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Finalmente, unificamos todo en una función que toma un mapa de URLs y nos devuelve el objeto final usando &lt;code&gt;Object.fromEntries&lt;/code&gt;:&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;clientGenerator&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ServiceMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;R&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="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Client&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;connector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Connector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;services&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="nx"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseURL&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;)]),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
   El "Perfect Match": RSC y React Query
&lt;/h2&gt;

&lt;p&gt;Donde esto realmente brilla es en el frontend moderno.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Server Components (RSC)
&lt;/h3&gt;

&lt;p&gt;Esta estrategia casa perfectamente con la filosofía de tener &lt;a href="https://dev.to/x0s3/one-api-to-rule-them-all-587n"&gt;One API to rule them all&lt;/a&gt;. En entornos con Server Components, quieres que tus llamadas a la API sean lo más planas y directas posibles.&lt;/p&gt;

&lt;p&gt;Al centralizar todo en un generador, tus componentes de servidor se mantienen limpios de lógica de infraestructura, delegando el manejo de tokens, certificados o headers de tracking al connector base.&lt;/p&gt;

&lt;h3&gt;
  
  
   Integración con React Query
&lt;/h3&gt;

&lt;p&gt;La integración aquí es increíble. Como el generador devuelve una promesa tipada, react-query infiere el tipo de data automáticamente:&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="c1"&gt;// El tipado de 'data' se hereda de la respuesta del cliente automáticamente&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fines&lt;/span&gt;&lt;span class="dl"&gt;'&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="na"&gt;queryFn&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;fines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FinesDetail&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/fines/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto elimina la necesidad de declarar genéricos manualmente en cada useQuery y asegura que lo que dice tu API sea exactamente lo que llega a tus componentes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Al abstraer la creación de clientes con un generador centralizado, no solo limpias tu código de infraestructura, sino que garantizas que todos los microservicios de tu ecosistema se consuman bajo las mismas reglas (mismos headers, mismo manejo de errores, mismo tracking).&lt;/p&gt;

&lt;p&gt;Es una inversión pequeña en arquitectura que paga dividendos enormes en mantenibilidad y &lt;strong&gt;Developer Experience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Qué les parece este enfoque? ¿Usan Proxies en sus utils o prefieren definiciones más explícitas?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>architecture</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>One API to Rule Them All</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Thu, 11 Sep 2025 16:02:07 +0000</pubDate>
      <link>https://forem.com/x0s3/one-api-to-rule-them-all-587n</link>
      <guid>https://forem.com/x0s3/one-api-to-rule-them-all-587n</guid>
      <description>&lt;h2&gt;
  
  
  One API to Rule Them All: Unificando Logs y Más en Proyectos de Gran Escala
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introducción: El Caos de las APIs Dispersas
&lt;/h3&gt;

&lt;p&gt;En proyectos de software con múltiples equipos y un ciclo de vida largo, la fragmentación de las APIs es un problema recurrente. Cada equipo, o incluso cada desarrollador, puede optar por diferentes librerías o enfoques para tareas comunes: logs, manejo de errores, peticiones HTTP, etc. Esto no solo introduce inconsistencias, sino que también aumenta la complejidad de mantenimiento, dificulta el &lt;em&gt;onboarding&lt;/em&gt; de nuevos miembros y, en última instancia, ralentiza el desarrollo.&lt;/p&gt;

&lt;p&gt;Imaginemos un escenario donde el logging en el frontend usa &lt;code&gt;console.log&lt;/code&gt; o una librería específica, mientras que el backend usa otra distinta, quizás con diferentes niveles y formatos. Si necesitas centralizar los logs, o cambiar la implementación subyacente, te enfrentas a una tarea titánica.&lt;/p&gt;

&lt;p&gt;La solución reside en la &lt;strong&gt;unificación&lt;/strong&gt;. Crear una "One API to Rule Them All" para ciertas funcionalidades clave puede transformar la forma en que los equipos interactúan con el sistema.&lt;/p&gt;




&lt;h3&gt;
  
  
  Caso de Estudio: Unificando el Sistema de Logs
&lt;/h3&gt;

&lt;p&gt;El sistema de logs es un candidato perfecto para la unificación. Es transversal a cualquier parte de nuestra aplicación, ya sea en el cliente (navegador, React Native) o en el servidor (Node.js).&lt;/p&gt;

&lt;h4&gt;
  
  
  El Problema sin Unificación
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistencia:&lt;/strong&gt; &lt;code&gt;console.log&lt;/code&gt;, &lt;code&gt;console.warn&lt;/code&gt;, &lt;code&gt;debug&lt;/code&gt;, &lt;code&gt;pino&lt;/code&gt;, &lt;code&gt;winston&lt;/code&gt;, &lt;code&gt;log4js&lt;/code&gt;. Cada uno con su sintaxis y capacidades.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mantenimiento:&lt;/strong&gt; Si cambiamos el sistema de logs (ej. de un &lt;em&gt;file system&lt;/em&gt; a un &lt;em&gt;cloud service&lt;/em&gt;), debemos modificar código en múltiples lugares y plataformas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacitación:&lt;/strong&gt; Los nuevos desarrolladores deben aprender múltiples herramientas de logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralización:&lt;/strong&gt; Es difícil consolidar y analizar logs de diferentes fuentes con formatos dispares.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  La Solución: Una Interfaz Unificada
&lt;/h4&gt;

&lt;p&gt;Podemos crear una API de logging sencilla y agnóstica de la implementación. El objetivo es que los desarrolladores solo necesiten aprender una interfaz.&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="c1"&gt;// src/infrastructure/log/index.ts&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;LogLevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LoggerInterface&lt;/span&gt;
  &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&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;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LoggerInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&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;await&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="s2"&gt;./client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;BrowserLogger&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&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="s2"&gt;./server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;ServerLogger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Consejo del abuelo: Entornos como Bun, Cloudflare, Deno definen un objeto window similar al del navegador, aunque no estén ejecutándose en un navegador web. Esto lo hacen para mantener la compatibilidad con el código JavaScript que espera la presencia de este objeto global. Por lo tanto el único que tiene &lt;code&gt;document&lt;/code&gt; (es decir elementos html) es el navegador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Con esta interfaz, cualquier parte de nuestro código, ya sea en el cliente o en el servidor, solo necesita importar &lt;code&gt;log&lt;/code&gt; y usar sus métodos.&lt;/p&gt;




&lt;h3&gt;
  
  
  La Magia de los Bundlers: Implementaciones Específicas para Cada Entorno
&lt;/h3&gt;

&lt;p&gt;La belleza de esta arquitectura se maximiza con &lt;em&gt;bundlers&lt;/em&gt; modernos como &lt;strong&gt;Turbopack&lt;/strong&gt; y &lt;strong&gt;Vite&lt;/strong&gt;. Estos nos permiten tener múltiples implementaciones para la misma interfaz, y el &lt;em&gt;bundler&lt;/em&gt; se encarga de empaquetar solo el código relevante para el entorno final (cliente o servidor).&lt;/p&gt;

&lt;p&gt;Esto se logra gracias a técnicas como el &lt;strong&gt;Tree Shaking&lt;/strong&gt; o la &lt;strong&gt;eliminación de código muerto&lt;/strong&gt;. Cuando el &lt;em&gt;bundler&lt;/em&gt; procesa el código para el cliente, se da cuenta de que la implementación del &lt;em&gt;logger&lt;/em&gt; para el servidor nunca es utilizada y, por lo tanto, la elimina por completo del &lt;em&gt;bundle&lt;/em&gt; final, resultando en un paquete más pequeño y optimizado. Lo mismo ocurre en el lado del servidor, donde la implementación del cliente es descartada.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementación para el Navegador (Cliente):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/intrastructure/log/browserLogger.ts&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;client only&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LoggerInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LogLevel&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;./&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;formatMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;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="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&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="nx"&gt;message&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="nx"&gt;context&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="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;BrowserLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LoggerInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// Sentry/Datadog/Bugsnag implementation&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// Sentry/Datadog/Bugsnag implementation&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Sentry/Datadog/Bugsnag implementation&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;
  
  
  Implementación para el Servidor (Node.js):
&lt;/h4&gt;

&lt;p&gt;Aquí podemos usar librerías robustas como &lt;code&gt;pino&lt;/code&gt; o &lt;code&gt;winston&lt;/code&gt;.&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="c1"&gt;// src/infrastructure/log/server.ts&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server only&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LoggerInterface&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;./log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pino&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;pino&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;pinoLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pino&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&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;LOG_LEVEL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pino-pretty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;colorize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ServerLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LoggerInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pinoLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pinoLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pinoLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El patrón clave aquí es diferenciar el entorno desde donde vamos a ejecutar nuestro logger, lo que permite a los &lt;em&gt;bundlers&lt;/em&gt; como Next.js y Vite optimizar el código para cada entorno.&lt;/p&gt;




&lt;h3&gt;
  
  
  Beneficios Tangibles de la Unificación
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Consistencia:&lt;/strong&gt; El código se ve y se comporta de manera similar en todo el proyecto.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Mantenimiento Simplificado:&lt;/strong&gt; Los cambios en la implementación de una API se hacen en un solo lugar.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Facilidad de Testing:&lt;/strong&gt; Las interfaces claras facilitan la creación de &lt;em&gt;mocks&lt;/em&gt; y pruebas unitarias.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Menor Curva de Aprendizaje:&lt;/strong&gt; Los nuevos desarrolladores solo necesitan aprender la API unificada, no múltiples herramientas.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reusabilidad del Código:&lt;/strong&gt; La lógica de negocio puede ser más agnóstica a la plataforma.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Desacoplamiento:&lt;/strong&gt; El código que usa la API está desacoplado de su implementación específica.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusión
&lt;/h3&gt;

&lt;p&gt;Adoptar el patrón "One API to Rule Them All" para funcionalidades transversales es una inversión que rinde frutos a largo plazo en proyectos complejos. Reduce la fricción, mejora la calidad del código y, gracias a las capacidades de optimización de &lt;em&gt;bundlers&lt;/em&gt; como &lt;strong&gt;Vite&lt;/strong&gt; y &lt;strong&gt;Webpack/Turbopack&lt;/strong&gt;, nos permite mantener un código limpio y unificado sin sacrificar el rendimiento. Empezar con el sistema de logs es un excelente primer paso para demostrar el valor de esta estrategia.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Gradual React-Router-Dom Upgrades (complex case)</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Tue, 10 Jan 2023 13:49:56 +0000</pubDate>
      <link>https://forem.com/x0s3/gradual-react-router-dom-upgrades-complex-case-2nl5</link>
      <guid>https://forem.com/x0s3/gradual-react-router-dom-upgrades-complex-case-2nl5</guid>
      <description>&lt;h1&gt;
  
  
  Demo of Gradual React-Router-Dom Upgrades 🪢🪡
&lt;/h1&gt;

&lt;p&gt;This is a demo of how you can configure a build system to serve &lt;strong&gt;two different versions of React-Router-Dom&lt;/strong&gt; side by side in the same app. This is not optimal, and should only be used as a compromise to prevent your app from getting stuck on an old version of React-Router-Dom.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://reactjs.org/blog/2020/08/10/react-v17-rc.html#gradual-upgrades"&gt;Learn more about Gradual Upgrades.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I highly recommend using their backward compatible library, it's amazing! &lt;a href="https://github.com/remix-run/react-router/tree/main/packages/react-router-dom-v5-compat"&gt;compat-lib&lt;/a&gt;, congratulations to the team for their wonderful work and how easy they made everything!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why NOT Do This 🙅‍♂️
&lt;/h2&gt;

&lt;p&gt;Note that &lt;strong&gt;this approach is meant to be an escape hatch, not the norm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Normally, React team encourage us to use a single version of libs across our whole app. When we need to upgrade React-Router-Dom, it is better to try to upgrade it all at once.&lt;/p&gt;

&lt;p&gt;Using a single version of React-Router-Dom removes a lot of complexity. It is also essential to ensure the best experience for our users who don't have to download the code twice. &lt;strong&gt;Always prefer using one Router if you can.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do This 🕺
&lt;/h2&gt;

&lt;p&gt;However, for some apps that have been in production for many years, upgrading all routes at once may be prohibitively difficult. For example, if the application code does not follow consistency in representing the application's routes or does not have a good test coverage.&lt;/p&gt;

&lt;p&gt;Traditionally, this meant that if a legacy API is deprecated, we would be stuck on the old version of React-Router-Dom forever. That prevents our whole app from receiving improvements and bugfixes. This repository demonstrates a hybrid approach. It shows how we can use a newer version of React-Router-Dom for some parts of our app, while &lt;strong&gt;lazy-loading an older version of React-Router-Dom&lt;/strong&gt; for the parts that haven't been migrated yet.&lt;/p&gt;

&lt;p&gt;This approach is inherently more complex, and should be used as a last resort when we can't upgrade.&lt;/p&gt;

&lt;p&gt;We have to options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We either wail until the entire application is migrated with the new Router or&lt;/li&gt;
&lt;li&gt;We can apply the well known strangler pattern to our frontend application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;strangler pattern&lt;/em&gt; comes from the idea of generating incremental value for the business and the user by releasing parts of the applications instead of waiting for the wholly new application to be ready.&lt;/p&gt;

&lt;p&gt;Basically, with this gradual upgrade, we can tackle an area of the app where we think we may generate value for the business, build with the new features/router, and deploy them in the production environment living alongside the legacy application. Besides, by doing it incrementally we avoid introducing bugs and in case of failure it is much easier to perform a rollback of the route.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This way we can wait for the team that maintains the library to incorporate the &lt;code&gt;Prompt&lt;/code&gt; functionality again 😜&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Version Requirements 🎬
&lt;/h2&gt;

&lt;p&gt;This demo uses two different versions of React-Router-Dom: RRD 6 for "modern" routes (in &lt;code&gt;src/modern&lt;/code&gt;), and RRD 5 for "legacy" routes (in &lt;code&gt;src/legacy&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I still recommend upgrading the entire application to RRD 6 at once.&lt;/strong&gt; The remix team, has created some migration guidelines and even a compat layer, but sometimes we are not always fortunate enough to be able to carry out these migrations in the way they are proposed.&lt;/p&gt;

&lt;p&gt;However, if you're already stuck on an old version of RRD, you may found this approach useful today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;keep in mind that the usage of third-party libraries included in this demo (React-Router-Dom) may need to be adjusted or removed 👍&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installation 👷‍♂️
&lt;/h2&gt;

&lt;p&gt;To run this demo, clone the project, open its folder and execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to test the production build, you can run instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i
npm run build
npx serve -s build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to analyze the production build, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i
npm run build
npm run analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sample app uses client-side routing and consists of five routes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; renders a page which uses a newer version of React-Router-Dom&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/users/:id&lt;/code&gt; renders a page which uses new features such a &lt;code&gt;defer&lt;/code&gt; and &lt;code&gt;loader&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/about&lt;/code&gt; renders a page which uses an older version of React-Router-Dom for a part of its tree. (In the production build, you can verify that both versions of React-Router-Dom are loaded from different chunks.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/dashboard&lt;/code&gt; renders a page which uses an older version of React-Router-Dom for a part of its tree. (In the production build, you can verify that both versions of React-Router-Dom are loaded from different chunks.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/error&lt;/code&gt; renders a page which uses a newer version of React-Router-Dom and catches all non-existent routes in both systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The purpose of this demo is to show some nuances of such setup:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to install two versions of React-Router-Dom in a single app with npm side by side&lt;/li&gt;
&lt;li&gt;How to avoid the &lt;a href="https://github.com/facebook/react/issues/13991"&gt;"invalid Hook call" error&lt;/a&gt; while nesting React trees&lt;/li&gt;
&lt;li&gt;How to pass context between different systems&lt;/li&gt;
&lt;li&gt;How to lazy-load the second React bundle so it's only loaded on the routes that use it&lt;/li&gt;
&lt;li&gt;How to do all of this without a special bundler configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works 👨‍🏫
&lt;/h2&gt;

&lt;p&gt;File structure is extremely important in this demo. It has a direct effect on which code is going to use which version of React. This particular demo is using Create React App without ejecting, so &lt;strong&gt;it doesn't rely on any bundler plugins or configuration&lt;/strong&gt;. The principle of this demo is portable to other setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependencies 🏭
&lt;/h3&gt;

&lt;p&gt;We will use three different &lt;code&gt;package.json&lt;/code&gt;s: one for non-React code at the root, and two in the respective &lt;code&gt;src/legacy&lt;/code&gt; and &lt;code&gt;src/modern&lt;/code&gt; folders that specify the React dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;: The root &lt;code&gt;package.json&lt;/code&gt; is a place for build dependencies (such as &lt;code&gt;react-scripts&lt;/code&gt;) and any React-agnostic libraries (for example, &lt;code&gt;lodash&lt;/code&gt;, &lt;code&gt;immer&lt;/code&gt;, or &lt;code&gt;redux&lt;/code&gt;). We do &lt;strong&gt;not&lt;/strong&gt; include React or any React-related libraries in this file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/legacy/package.json&lt;/code&gt;&lt;/strong&gt;: This is where we declare the &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom&lt;/code&gt; dependencies for the "legacy" trees. In this demo, we're using React-Router-Dom 5.3.4 (although, as noted above, we could downgrade it further below). This is &lt;strong&gt;also&lt;/strong&gt; where we specify any third-party libraries that use React. For example, &lt;code&gt;react-redux&lt;/code&gt; or other libs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/modern/package.json&lt;/code&gt;&lt;/strong&gt;: This is where we declare the &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom&lt;/code&gt; dependencies for the "modern" trees. In this demo, we're using React-Router-Dom 6.6.1. Here, we also specify third-party dependencies that use React and are used from the modern part of our app. This is why we &lt;em&gt;also&lt;/em&gt; have &lt;code&gt;react-router-dom&lt;/code&gt; in this file. (Their versions don't strictly have to match their &lt;code&gt;legacy&lt;/code&gt; counterparts, but features that rely on context may require workarounds if they differ, in this case, the contexts follow the same structure and we don't have to make any custom compat layer v6-&amp;gt;v5.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;scripts&lt;/code&gt; in the root &lt;code&gt;package.json&lt;/code&gt; are set up so that when you run &lt;code&gt;npm install&lt;/code&gt; in it, it also runs &lt;code&gt;npm intall&lt;/code&gt; in both &lt;code&gt;src/legacy&lt;/code&gt; and &lt;code&gt;src/modern&lt;/code&gt; folders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Folders 📁
&lt;/h3&gt;

&lt;p&gt;There are a few key folders in this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src&lt;/code&gt;&lt;/strong&gt;: Root of the source tree. At this level (or below it, except for the special folders noted below), you can put any logic that's agnostic of React. For example, in this demo we have &lt;code&gt;src/index.js&lt;/code&gt; which is the app's entry point. These regular modules only execute once, and are &lt;strong&gt;not&lt;/strong&gt; duplicated between the bundles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/legacy&lt;/code&gt;&lt;/strong&gt;: This is where all the code using the older version of React should go. This includes React components and Hooks, and general product code that is &lt;strong&gt;only&lt;/strong&gt; used by the legacy trees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/modern&lt;/code&gt;&lt;/strong&gt;: This is where all the code using the newer version of React should go. This includes React components and Hooks, and general product code that is &lt;strong&gt;only&lt;/strong&gt; used by the modern trees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;src/shared&lt;/code&gt;&lt;/strong&gt;: You may have some components or Hooks that you wish to use from both modern and legacy subtrees. The build process is set up so that &lt;strong&gt;everything inside &lt;code&gt;src/shared&lt;/code&gt; gets copied by a file watcher&lt;/strong&gt; into both &lt;code&gt;src/legacy/shared&lt;/code&gt; and &lt;code&gt;src/modern/shared&lt;/code&gt; on every change. This lets you write a component or a Hook once, but reuse it in both places.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lazy Loading 📩
&lt;/h3&gt;

&lt;p&gt;Loading two Reacts on the same page is bad for the user experience, so we should strive to push this as far as possible from the critical path of our app. For example, if there is a route that is rarely visited, those are better candidates for staying on an older version of React-Router-Dom than parts of our homepage.&lt;/p&gt;

&lt;p&gt;To encourage only loading the older React-Router-Dom when necessary, this demo includes a helper that works similarly to &lt;code&gt;React.lazy&lt;/code&gt;. For example, &lt;code&gt;src/modern/LegacyApp.js&lt;/code&gt;, simplified, looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;lazyLegacyRoot&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;./lazyLegacyRoot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Lazy-load a component from the bundle using legacy Router&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LegacyAppBridge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lazyLegacyRoot&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="s2"&gt;../legacy/LegacyApp&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;function&lt;/span&gt; &lt;span class="nx"&gt;LegacyApp&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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;modern&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;LegacyBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt; &lt;span class="err"&gt;🚨&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;outer&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Dom&lt;/span&gt; &lt;span class="nx"&gt;v6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;6.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LegacyAppBridge&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;As a result, only if the &lt;code&gt;/about&lt;/code&gt; page gets rendered, we will load the bundle containing the legacy Router and the legacy &lt;code&gt;AboutPage&lt;/code&gt; component. Like with &lt;code&gt;React.lazy()&lt;/code&gt;, we wrap it in &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; to specify the loading indicator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Spinner&lt;/span&gt; &lt;span class="o"&gt;/&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LegacyAppBridge&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the legacy component is only rendered conditionally, we won't load the second Router until it's shown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&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;setShowGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;Say&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showGreeting&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Spinner&lt;/span&gt; &lt;span class="o"&gt;/&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation of the &lt;code&gt;src/modern/lazyLegacyRoot.js&lt;/code&gt; helper is included so we can tweak it and customize it to our needs. Remember to test lazy loading with the production builds because the bundler may not optimize it in development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Navigating between routes of different systems 🏄‍♂️
&lt;/h3&gt;

&lt;p&gt;It is very likely that at some point we will need to redirect our users from a migrated route to a legacy route and vice versa.&lt;/p&gt;

&lt;p&gt;To do this, it must be remembered that the navigation performed and managed by &lt;strong&gt;React-Router-Dom&lt;/strong&gt; is relative to the context where it is being rendered.&lt;br&gt;
That is, if the user is in the old system and wants to navigate to a page which is totally managed by the new system, if we make use of &lt;code&gt;Link&lt;/code&gt; or &lt;code&gt;history.push&lt;/code&gt; it will not work as expected because it will look for the path in the &lt;code&gt;Switch&lt;/code&gt; of the old system.&lt;/p&gt;

&lt;p&gt;Therefore, to perform such navigations, we must delegate the responsibility of performing those navigations to the native html, using an anchor (aka &lt;code&gt;&amp;lt;a href="/path/en/new/system" /&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;by using an anchor we have the disadvantage that all requests will be performed again and the current status on the client side will be lost 😰 but we can fix that 🤫&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  With DI 🌈
&lt;/h4&gt;

&lt;p&gt;If we find the need to navigate without having to lose the current status of the application and prevent unnecessary requests, we have a solution for this problem ✌️&lt;/p&gt;

&lt;p&gt;Basically we will inject the &lt;code&gt;navigate&lt;/code&gt; function of the new system into one of the legacy system contexts, this is totally licit to do, since executing a function is possible in JavaScript 😜&lt;/p&gt;

&lt;p&gt;i.e:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: this is an example and for this reason best practices are not used, in our projects do it calmly and following the best possible practices 🥶&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./src/modern/lazyLegacyRoot.js&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;useNavigate&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;react-router-dom&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="nx"&gt;lazyLegacyRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useNavigate&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./src/legacy/createLegacyRoot.js&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;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useContext&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;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;ModernBridge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useModernBridge&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;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ModernBridge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Bridge&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;context&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ModernBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;__RouterContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&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;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/__RouterContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ModernBridge.Provider&lt;/span&gt;&lt;span class="err"&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;// ./src/legacy/LegacyApp.js&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;useModernBridge&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;./createLegacyRoot&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="nx"&gt;AboutPageLegacy&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;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useModernBridge&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/120&lt;/span&gt;&lt;span class="dl"&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;Navigate&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;modern&lt;/span&gt; &lt;span class="nx"&gt;system&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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;In this way, the state of our application remains intact and the navigation is performed by our new routing system 🤭.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;but be careful not to mix too much, there is a fine line that separates the lawful from a failed production 🤪&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Context 🏗
&lt;/h3&gt;

&lt;p&gt;If we have nested trees managed by different versions of React-Router-Dom, the inner tree won't "see" the outer tree's Contexts.&lt;/p&gt;

&lt;p&gt;This breaks third-party libraries like React-Redux or React-Router, as well as any of our own usage of Context (for example, for theming or auth).&lt;/p&gt;

&lt;p&gt;To solve this problem, we read all the Contexts we care about in the outer tree, pass them to the inner tree, and then wrap the inner tree in the corresponding Providers. We can see this in action in two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/modern/lazyLegacyRoot.js&lt;/code&gt;: Look for &lt;code&gt;useContext&lt;/code&gt; calls, and how their results are combined into a single object that is passed through. &lt;strong&gt;We can read more Contexts there&lt;/strong&gt; if our app requires them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/legacy/createLegacyRoot.js&lt;/code&gt;: Look for the &lt;code&gt;Bridge&lt;/code&gt; component which receives that object and wraps its children with the appropriate Context Providers. &lt;strong&gt;We can wrap them with more Providers there&lt;/strong&gt; if our app requires them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that, generally saying, this approach is somewhat fragile, especially because some libraries may not expose their Contexts officially or consider their structure private. We may be able to expose private Contexts by using a tool like &lt;a href="https://www.npmjs.com/package/patch-package"&gt;patch-package&lt;/a&gt;, but remember to keep all the versions pinned because even a patch release of a third-party library may change the behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nesting Direction ↩️
&lt;/h3&gt;

&lt;p&gt;In this demo, we use an older Router inside an app managed by the newer Router. However, we could rename the folders and apply the same approach in the other direction.&lt;br&gt;
It all depends on the degree of dependency of the application, such as state management, layouts, etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Personally, doing it from the outside in is much simpler since at the end there will come a point when the legacy folder is empty and all we have to do is delete it and return to the initial state, just a &lt;code&gt;src&lt;/code&gt; folder 😉 (also known as &lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html"&gt;Strangler Pattern&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Gotchas 🕵️‍♂️
&lt;/h2&gt;

&lt;p&gt;This setup is unusual, so it has a few gotchas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't add &lt;code&gt;package.json&lt;/code&gt; to the &lt;code&gt;src/shared&lt;/code&gt; folder. For example, if we want to use an npm React component inside &lt;code&gt;src/shared&lt;/code&gt;, we should add it to both &lt;code&gt;src/modern/package.json&lt;/code&gt; and &lt;code&gt;src/legacy/package.json&lt;/code&gt; instead. We can use different versions of it but make sure our code works with both of them — and that it works with both Reacts!&lt;/li&gt;
&lt;li&gt;Don't use React outside of the &lt;code&gt;src/modern&lt;/code&gt;, &lt;code&gt;src/legacy&lt;/code&gt;, or &lt;code&gt;src/shared&lt;/code&gt;. Don't add React-related libraries outside of &lt;code&gt;src/modern/package.json&lt;/code&gt; or &lt;code&gt;src/legacy/package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remember that &lt;code&gt;src/shared&lt;/code&gt; is where we write shared components, but the files we write there are automatically copied into &lt;code&gt;src/modern/shared&lt;/code&gt; and &lt;code&gt;src/legacy/shared&lt;/code&gt;, &lt;strong&gt;from which we should import them&lt;/strong&gt;. Both of the target directories are in &lt;code&gt;.gitignore&lt;/code&gt;. Importing directly from &lt;code&gt;src/shared&lt;/code&gt; &lt;strong&gt;will not work&lt;/strong&gt; because it is ambiguous what &lt;code&gt;react&lt;/code&gt; refers to in that folder&lt;/li&gt;
&lt;li&gt;Keep in mind that any code in &lt;code&gt;src/shared&lt;/code&gt; gets duplicated between the legacy and the modern bundles. Code that should not be duplicated needs to be anywhere else in &lt;code&gt;src&lt;/code&gt; (but we can't use React there since the version is ambiguous)&lt;/li&gt;
&lt;li&gt;We'll want to exclude &lt;code&gt;src/*/node_modules&lt;/code&gt; from our linter's configuration, as this demo does in &lt;code&gt;.eslintignorerc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Many points mentioned in the list can be solved by adapting our bundler, such as webpack, and resolving the packages so that they are not duplicated when the application is compiled&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This setup is complicated, and is not recommended for most apps. However, I believe it is important to offer it as an option for apps that would otherwise get left behind.&lt;br&gt;
There might be better ways to perform such migrations, but having another alternative as an example is always a good thing ☺️.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few of my own considerations 🤠
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Better not to delegate the status of the application to the router status (saves a lot of unnecessary headaches)&lt;/li&gt;
&lt;li&gt;To avoid extremely complexities in handling global states, I highly recommend the use of tools like &lt;a href="https://jotai.org/"&gt;&lt;code&gt;jotai&lt;/code&gt;&lt;/a&gt;, apart that we can import this from either folder without duplicating the object/state! 😲&lt;/li&gt;
&lt;li&gt;Please, for this to come out with an erotic result, I will not tire of recommending to add observability to our architecture, observability closes the feedback loop when our code runs in a production environment; otherwise, we would not be able to react quickly to any incidents happening durint prime time. (is a must-have feature! 🙏)&lt;/li&gt;
&lt;li&gt;Draw up a plan of action to migrate all the routes in a certain period of time, and determine which routes will be the first, it is always good to set a date to force us to work on it and that this migration does not remain in an application with both systems coexisting forever, thus being a new Frankestein 🧟‍♂️&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Credits to the React team for this great alternative to make changes to legacy applications in an incremental and painless way also to the remix team for react router dom compatibilities between versions 💚&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repo can be found &lt;a href="https://github.com/x0s3/react-router-dom-advanced-migration"&gt;here&lt;/a&gt; ✌️&lt;/p&gt;

</description>
      <category>react</category>
      <category>architecture</category>
      <category>writing</category>
    </item>
    <item>
      <title>Reinforcing confidence in our code</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Tue, 06 Dec 2022 11:04:56 +0000</pubDate>
      <link>https://forem.com/x0s3/reinforcing-confidence-in-our-code-o18</link>
      <guid>https://forem.com/x0s3/reinforcing-confidence-in-our-code-o18</guid>
      <description>&lt;h1&gt;
  
  
  Test coverage 📉 🔜 📈
&lt;/h1&gt;

&lt;p&gt;I'll start by sharing what test coverage is with what someone once explained to me with the following analogy:&lt;/p&gt;

&lt;h2&gt;
  
  
  Warm up == Testing 🧥
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The percentage of skin we cover to keep warm is the Code Coverage&lt;/li&gt;
&lt;li&gt;No need to cover up completely to keep out the cold and &amp;lt;100% coverage is fine&lt;/li&gt;
&lt;li&gt;The ability of the garment to protect us from the cold is the quality of the test&lt;/li&gt;
&lt;li&gt;If we wear several layers of clothing, we have duplicate tests, but sometimes it is convenient to cover ourself with more than one garment, each with its own purpose&lt;/li&gt;
&lt;li&gt;There are uncomfortable clothes, difficult to take off and put on. There are uncomfortable and difficult to maintain tests&lt;/li&gt;
&lt;li&gt;If we have to take off all our clothes and get cold to pee, we are suffering from coupled tests&lt;/li&gt;
&lt;li&gt;There are garments that do not last, as well as tests, which can be fragile&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Extra point&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;We can bundle up at home and then go outside (TDD), or we can go outside and wait until we are cold 🥶&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, &lt;a href="https://youtu.be/nCg3ufihKyU?t=76" rel="noopener noreferrer"&gt;let's get down to business&lt;/a&gt; 🕵️‍♂️&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we are today 🏚
&lt;/h2&gt;

&lt;p&gt;Following the points mentioned above, currently our code coverage is almost non-existent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DISCLAIMER: ⚠️ &lt;strong&gt;This is fake data&lt;/strong&gt; ⚠️&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=============================== Coverage summary ===============================
Statements   : 15.53% ( 2732/17590 )
Branches     : 13.17% ( 946/7179 )
Functions    : 11.85% ( 613/5169 )
Lines        : 15.72% ( 2635/16752 )
================================================================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we review a little more, we can see that more than half of our project has a.... &lt;strong&gt;¡0%!&lt;/strong&gt; 🚨&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%2F82un2giviavivkqvzaoh.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%2F82un2giviavivkqvzaoh.png" alt="No_coverage" width="720" height="754"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and if we review that 41%, we find that only 56 files have a good coverage (only 12% of our code 😱):&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%2Fg6cvk5zlw4am5lm74on5.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%2Fg6cvk5zlw4am5lm74on5.png" alt="With_coverage" width="720" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it important?
&lt;/h2&gt;

&lt;p&gt;As engineers we have to care and make sure that our code is functional for our users and that the requirements set by product are met without errors.&lt;/p&gt;

&lt;p&gt;One thing I like to think about is that we as software engineers have to make sure that both product and user expectations are met in a realistic way, and one of the tools we have to accomplish that task under our belt is programming.&lt;/p&gt;

&lt;p&gt;Therefore, we have to think not only about the present, but beyond that and think about our future and the future partners who will have to take over the project. That is why one of the tools that we also have at our disposal is to check that our code works, and not just now, but over time, and this is very important because it is where over time is where the benefits of the effort in writing tests can be seen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps 👣
&lt;/h2&gt;

&lt;p&gt;Knowing where we are starting from, let's make a joint approach on how we can increase this lack of coverage.&lt;/p&gt;

&lt;p&gt;Here are a few points as entry points to the discussion/brainstorming 🧠:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on &lt;em&gt;case coverage&lt;/em&gt;* rather than code coverage&lt;/li&gt;
&lt;li&gt;All new code must have tests&lt;/li&gt;
&lt;li&gt;If any file is modified, a test case should be added for that case&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;case coverage&lt;/em&gt;&lt;/strong&gt;*: Since this is a project that is generating revenue and there are thousands of users using it, it will be best to initially focus our energy on covering all those parts that are most important for the proper functioning of the application. The best way to do this is to talk to the stakeholders and find out which of these parts need to be covered with the highest priority.&lt;/p&gt;

&lt;p&gt;e.g: If something stopped working, what part would you wish it didn't?&lt;/p&gt;

&lt;p&gt;e.g: Which part would have the most impact if it were temporarily down?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once we know what we have to reinforce first, we will have to make an analysis of the code and know if we are facing a case of &lt;a href="https://martinfowler.com/bliki/Detestable.html" rel="noopener noreferrer"&gt;detestable&lt;/a&gt; code or not, since it is not the same to invest hours and hours in testing something fragile (as mentioned at the beginning) than to look for alternatives and iterate little by little until we have something reliable ⭐.&lt;/p&gt;

&lt;p&gt;Since depending on that we will have to apply E2E first and once they are working, we can perform a refactor in that part of the code with the assurance that we will not break anything or introduce regressions, and as the new code must be better than the previous and is intended to be testable we will have both E2E (happy path) and unit tests/integration that will give us the security and confidence that we were missing 🥰.&lt;/p&gt;

&lt;p&gt;In future posts we will talk about how to analyze our code to know which parts are urgently asking for a refactor and how to approach this task.&lt;/p&gt;

&lt;p&gt;C u in the next post! 🫶💚 (&lt;em&gt;and don't forget to drink 2L of water per day!&lt;/em&gt;)&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%2F9a5ubhm0eww48xwcy17c.gif" 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%2F9a5ubhm0eww48xwcy17c.gif" alt="GetRidOfTheBugs" width="250" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Rethinking the reducer pattern 🧑‍🏭</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Tue, 29 Nov 2022 22:03:34 +0000</pubDate>
      <link>https://forem.com/x0s3/rethinking-the-reducer-pattern-jag</link>
      <guid>https://forem.com/x0s3/rethinking-the-reducer-pattern-jag</guid>
      <description>&lt;h1&gt;
  
  
  Reducers and DX 🧑‍🏭
&lt;/h1&gt;

&lt;p&gt;As an introduction to this topic, let's make a small reminder of what a reducer is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reducers are functions that take the current state and an action as arguments, and return a new state result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With that in mind, we can already get an idea that we can work with complex data structures or not, and be able to keep track of how the flow of our state works (aka the famous &lt;em&gt;one way data binding&lt;/em&gt; 😬).&lt;/p&gt;

&lt;p&gt;That said, let's go into a little more detail about how we can improve our reducers 🤠.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I highly recommend reading the new documentation of the useReducer hook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://beta.reactjs.org/learn/extracting-state-logic-into-a-reducer#"&gt;Extracting State Logic into a Reducer&lt;/a&gt; and &lt;a href="https://beta.reactjs.org/apis/react/useReducer"&gt;useReducer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where we are right now 😵
&lt;/h2&gt;

&lt;p&gt;Right now we are at a point where we don't know what's going on in our codebase, and worse, we don't know where the problems are coming from.&lt;/p&gt;

&lt;p&gt;We started to analyze all the code in detail and we realized from what we were told this morning at the standup that the error occurs when a user performs certain actions, so, we who are very smart, with that little information we can already get an idea that some data in one of these actions is being lost or corrupted.&lt;/p&gt;

&lt;p&gt;We get down to work and see that the code has a Switch with 900lines, with very nested state property assignments and side-effects 🤯&lt;/p&gt;

&lt;h3&gt;
  
  
  Not so cool reducer (code example):
&lt;/h3&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;useReducer&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;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;ADD_PRODUCT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ADD_PRODUCT&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;UPDATE_PRODUCT_STATUS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE_PRODUCT_STATUS&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;INITIAL_PRODUCTS_STATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;products&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;// this does not scale, is difficult to track and is very bug prone...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;INITIAL_PRODUCTS_STATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;ADD_PRODUCT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;products&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product&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;case&lt;/span&gt; &lt;span class="na"&gt;UPDATE_PRODUCT_STATUS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;products&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newStatus&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="nl"&gt;default&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;state&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="cm"&gt;/*
It might seem that our component is super easy, pretty and has hardly any lines of code, but it really hides a dark secret that can make us cry and pull our hair out in the near future...

What would happen if tomorrow we want to change the name of our action in the reducer? 🤔
And what happens if a component makes a mistake in dispatching the wrong action? 🤔
And what happens if we change the component that manages the products? 🤔
And if I have to make a change in the state in which I have to access a very deep property which has a nesting level that is more than 3 levels? 🤔
*/&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Example_withBadReducer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Current&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="nx"&gt;are&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductHandler&lt;/span&gt; &lt;span class="nx"&gt;dispatch&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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="cm"&gt;/*
 In the context of ProductHandler, what is the value of the "dispatch" property? What can I do with that prop? This component is highly coupled to the internal logic of the parent component, which is a bad thing.
*/&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ProductHandler&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="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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&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="s2"&gt;ADD_PRODUCT&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;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_permission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&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="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Initialize&lt;/span&gt; &lt;span class="nx"&gt;permission&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="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="s2"&gt;UPDATE_PRODUCT_STATUS&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;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_permission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;newStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FULL&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="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Change&lt;/span&gt; &lt;span class="nx"&gt;permission&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;h2&gt;
  
  
  Where we want to go 😍
&lt;/h2&gt;

&lt;p&gt;We do not want to have the best code in the world (in fact we want it but it is quite complicated), but to have the code that best suits our circumstances and that we are not afraid to touch in the future.&lt;/p&gt;

&lt;p&gt;But, what characteristics should a code have so that we are not afraid to work with it? &lt;em&gt;there are more but let's put those for now&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to understand and identify&lt;/li&gt;
&lt;li&gt;Easy to maintain and scale&lt;/li&gt;
&lt;li&gt;Easy to debug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take note of these 3 characteristics and see what we can do to achieve it 🫡.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducer with steroids (code example):
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;dependencies: &lt;code&gt;userImmer&lt;/code&gt; + &lt;a href="https://immerjs.github.io/immer/"&gt;&lt;code&gt;immer&lt;/code&gt;*&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;useMemo&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;react&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;useImmerReducer&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;use-immer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* 
Maybe this reminds us of Redux, but it is a mistake to link this only with Redux, since this is a pattern within the paradigm of functional languages, but that's another topic that we will not deal with now 🤪
*/&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useSelectors&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;mapStateToSelectors&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="nx"&gt;useMemo&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;mapStateToSelectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapStateToSelectors&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;function&lt;/span&gt; &lt;span class="nx"&gt;useActions&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;mapDispatchToActions&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="nx"&gt;useMemo&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;mapDispatchToActions&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="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;mapDispatchToActions&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="cm"&gt;/*
Pure functions that can be unit tested without any difficulty 🥰

The only drawback we have here is that our functions are coupled to exist within the context of immer, but under my point of view this is a lesser evil
*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ACTION_HANDLERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ADD_PRODUCT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;payload&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;UPDATE_PRODUCT_STATUS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;payload&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newStatus&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;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;products&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;function&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ACTION_HANDLERS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Example_withImmer&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;productsReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useImmerReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// May seem a bit verbose, but, if it does, perhaps you should not use a reducer 🥵&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;addProduct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;changeProductStatus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useActions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;productsReducer&lt;/span&gt;&lt;span class="p"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;addProduct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&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="s2"&gt;ADD_PRODUCT&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="nx"&gt;product&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;changeProductStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newStatus&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="s2"&gt;UPDATE_PRODUCT_STATUS&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newStatus&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getProducts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSelectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productsReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// here is where we should use `reselect`, `useCallback`/`useMemo` or a stable reference to our custom selectors function&lt;/span&gt;
    &lt;span class="na"&gt;getProducts&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// getProductById: (id) =&amp;gt; state.products?.[id]&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Current&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="nx"&gt;are&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;getProducts&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductHandler&lt;/span&gt;
        &lt;span class="nx"&gt;addProduct&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;addProduct&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;changeProductStatus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;changeProductStatus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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="cm"&gt;/*
 &amp;gt; Is an example to compare with the case we have been analyzing 🤓

 Instead of prop drilling the dispatch function, here we can see how our code now has a semantic relationship with our action, instead of making an act of faith and interpreting without certainty that the dispatch type is correct (e.g: a typo)*.

 Another problem of using the dispatch in a child component, is that this component should not necessarily know anything about the parent, it should only execute without taking into account the logic that its ancestor is handling.

 &amp;gt; * if we use TypeScript, many of these problems would disappear in dev/build time, since the compiler will tell us that something is wrong. 
*/&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ProductHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;addProduct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;changeProductStatus&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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&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;addProduct&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_permission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&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;Initialize&lt;/span&gt; &lt;span class="nx"&gt;permission&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;changeProductStatus&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_permission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;newStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FULL&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="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Change&lt;/span&gt; &lt;span class="nx"&gt;permission&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;As we can see in this new scenario, the code is much cleaner and more compact, we have the facility to update our state in a mutable way with the benefit that it will actually be done in an immutable way, without forgetting that we are no longer using an imperative control mechanism &lt;em&gt;ejem&lt;/em&gt; switch &lt;em&gt;ejem&lt;/em&gt; (and that is O(n)), but now we use a variant of a "hashmap" in JavaScript thanks to the properties of the objects (giving us O(1)).&lt;/p&gt;

&lt;p&gt;So, if we analyze this new version with the requirements we have previously set ourselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to understand and identify ✅
&amp;gt; By binding actions with their handlers we can give a name and a purpose to the functions that will generate a change in our state, in this way, we comply with the principle of least privilege, also known as &lt;strong&gt;PoLP&lt;/strong&gt;, basically our components will have the bare minimum privileges it needs to perform its intended function (and not the ability to be able to perform other actions without us knowing it, as in the previous case with the dispatch as a prop).&lt;/li&gt;
&lt;li&gt;Easy to maintain and scale ✅
&amp;gt; In our reducer, by making use of the object properties, we can find out much faster and without having to affect the rest of the cases if we add or remove any action, and thanks to the use of immer we can find out what purpose this action has in our state. And how wonderful it is to see that your child component is actually no longer coupled to the implementation of the parent, but is bound to the properties that it receives (much easier to modify, change and test).&lt;/li&gt;
&lt;li&gt;Easy to debug ✅
&amp;gt; Unwittingly, thanks to the previous modifications, we have managed to obtain a code that is much easier to debug and analyze, we have pure functions that are not complex at all and in the stacktrace we will have also available the name of the function which has caused the problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this scenario we find that we cannot normalize the data coming from the backend, or at least for now, so, thanks to using &lt;code&gt;immer&lt;/code&gt;* we drastically reduce the probability of screwing it up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Please always normalize the data, working with a flat structure is less prone to failure than having a data structure with deep-nested properties. &lt;a href="https://redux.js.org/usage/structuring-reducers/normalizing-state-shape"&gt;These people explain it very well&lt;/a&gt;, &lt;em&gt;although if you can have a &lt;a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/backends-for-frontends"&gt;BFF&lt;/a&gt; it is always much better than delegating the responsibility of managing the domain structures to the client side. (in another post we can discuss about how and where such data normalization can best be done 🤔)&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;As a personal conclusion, I think that reducers are a very powerful pattern but at the same time it is very complex to perform correctly, so I think that following these small guidelines within a professional environment can help a lot to identify what the code does and above all to avoid possible errors.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Mocking apollo hooks</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Wed, 30 Dec 2020 14:07:10 +0000</pubDate>
      <link>https://forem.com/x0s3/mocking-apollo-hooks-3gh</link>
      <guid>https://forem.com/x0s3/mocking-apollo-hooks-3gh</guid>
      <description>&lt;p&gt;&lt;a href="https://i.giphy.com/media/s0cEcMvEbzW7e/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/s0cEcMvEbzW7e/giphy.gif" alt="ImBackBbs" width="500" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pues bueno, parece que ha pasado ya más de un año desde mi última publicación (con una pandemia de por medio y mil catástrofes que parecía que se iba a acabar el mundo, o en su defecto el papel higiénico en los supermercados 🧻).&lt;/p&gt;

&lt;p&gt;Así que nada antes de empezar me gustaría felicitar a todos los lectores unas felices y seguras fiestas y que Papa Noel os haya traído muchas mascarillas! 🎅 😷&lt;/p&gt;

&lt;h3&gt;
  
  
  Manos a la obra!
&lt;/h3&gt;

&lt;p&gt;Una de las adversidades que he ido viendo en los proyectos que he estado trabajando y en la gente que lo forma, es la oscuridad que hay detrás de los mocks (en este caso de jest) y el cómo su uso nos puede beneficiar tanto en tiempo de desarrollo como a la hora de escribir nuestras pruebas unitarias.&lt;/p&gt;

&lt;p&gt;Un ejemplo que a primera vista parece MUY sencillo, luego a la hora de hacer sus pruebas unitarias puede llegar a ser enrevesado, el caso es el siguiente:&lt;/p&gt;

&lt;p&gt;Tenemos un component que queremos transformar sus props a un objeto mas "component friendly", para así luego renderizar nuestro html con dichas props ya mappeadas:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;dummy hook que nos facilita la vida (nos olvidamos del ApolloMockProvider y movidas varias)&lt;/em&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ApolloReactHooks&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;@apollo/react-hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;gql&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;graphql-tag&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;QUERY_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  query getUser {
    user {
      data {
        firstName
        lastName
        age
      }
    }
  }
`&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;function&lt;/span&gt; &lt;span class="nx"&gt;useGetUserLazyQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;baseOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApolloReactHooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;QueryHookOptions&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="nx"&gt;ApolloReactHooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useLazyQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;QUERY_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseOptions&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;em&gt;sí, lo sé, no he importado React, beneficios de usar React 17&lt;/em&gt; 😬&lt;/p&gt;

&lt;p&gt;&lt;em&gt;fake component que efectúa la llamada a nuestro backend y nos muestra por pantalla la información del usuario una vez recibida la query&lt;/em&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetUserLazyQuery&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;@hooks/useGetUserLazyQuery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;function&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;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;queryUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;called&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useGetUserLazyQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;onCompleted&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;age&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="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&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="nx"&gt;lastName&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="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;performQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;queryUser&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;called&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;loading&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;Loading ...&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="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;called&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;button&lt;/span&gt; &lt;span class="na"&gt;data-testid&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"load-users-btn"&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;performQuery&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Load user&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&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;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;li&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;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Age: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&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;li&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;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora viene dónde la matan, como podemos invocar el callback &lt;code&gt;onCompleted&lt;/code&gt; en nuestro caso? 🤔&lt;/p&gt;

&lt;p&gt;Que no cunda el pánico, no vamos a tener que hacer refactor de nuestro componente para que use un &lt;code&gt;useEffect&lt;/code&gt; para reaccionar al cambio de la prop &lt;code&gt;data&lt;/code&gt; ni nada por el estilo para que nuestro test pase ✅&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;waitFor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;userEvent&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;@testing-library/user-event&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;useGetUserLazyQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hooks/useGetUserLazyQuery&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;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hooks/useGetUserLazyQuery&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;useGetUserLazyQuery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fn&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;userMock&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Freddy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Krueger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;288&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;function&lt;/span&gt; &lt;span class="nx"&gt;renderComponent&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="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;mockQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;onCompletedHasBeenCalled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUserCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;useGetUserLazyQuery&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;d&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;// este condicional previene que la llamada a OnCompleted acabe en un bucle infinito y nos fastidie todo, únicamente lo ejecutaremos una única vez&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;onCompletedHasBeenCalled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onCompleted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;onCompletedHasBeenCalled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="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;getUserCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;called&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User component&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renders user data&lt;/span&gt;&lt;span class="dl"&gt;'&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;mockedQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userMock&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;renderComponent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findByTestId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load-users-btn&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="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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userMock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;waitFor&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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockedQuery&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalled&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;Toda la magia recae en &lt;a href="https://jestjs.io/docs/en/mock-function-api#mockfnmockimplementationfn"&gt;el mockImplementation&lt;/a&gt;, donde vamos a poder acceder a los argumentos que nuestro custom hook está recibiendo, de esta manera nos evitamos tener que mockear TODA la llamada que esperaría el provider de apollo, así pues, evitamos tener que renderizar componentes externos que para nuestra prueba unitaria no tiene mucho sentido, y nos podemos centrar exclusivamente en la funcionalidad de dicho componente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lo bueno si breve, dos veces bueno y aun lo malo, si poco, no tan malo
&lt;/h3&gt;

&lt;p&gt;Como diría el gran don Hector del Mar: &lt;em&gt;"Aquí estoy porque he venido, porque he venido aquí estoy, si no te gusta mi canto como he venido me voy"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Que tengáis una feliz entrada de 2021 donde los mocks de apollo no sean un problema!!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3o6EhGvKschtbrRjX2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3o6EhGvKschtbrRjX2/giphy.gif" alt="CYa!" width="480" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos vamos... pero volveremos!&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Módulos nativos para React-Native con Go (3/4)</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Tue, 03 Dec 2019 08:55:23 +0000</pubDate>
      <link>https://forem.com/x0s3/modulos-nativos-para-react-native-con-go-3-4-40o7</link>
      <guid>https://forem.com/x0s3/modulos-nativos-para-react-native-con-go-3-4-40o7</guid>
      <description>&lt;p&gt;Ánimo que en este post ya veremos nuestra app en funcionamiento sumando en Go!!&lt;/p&gt;

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

&lt;p&gt;En la parte de RN me he creado un hook para poder usar este módulo que lo he llamado &lt;em&gt;useNativeCounter&lt;/em&gt; (el código está en el &lt;a href="https://github.com/x0s3/react-native-go-examples/" rel="noopener noreferrer"&gt;repo&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Vamos a lo que nos interesa realmente, cómo hago yo para llamar a mis funciones de Go?&lt;/p&gt;

&lt;p&gt;Pues si hemos seguido el post anterior ya tenemos nuestros módulos linkeados en nuestro proyecto así que solo toca programar la parte del bridge.(llévame al punto de Android)&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS
&lt;/h2&gt;

&lt;p&gt;Como siempre, iOS es mucho mas simple de realizarlo que en Android muchas menos cosas a tener en cuenta y hacer.&lt;/p&gt;

&lt;p&gt;Creamos 2 archivos: el Header &lt;em&gt;SampleModule.h&lt;/em&gt; y los Métodos &lt;em&gt;SampleModule.m&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;en el archivo &lt;em&gt;SampleModule.h&lt;/em&gt; con poner lo siguiente es suficiente&lt;/p&gt;

&lt;p&gt;⚠️⚠️ "caution" ⚠️⚠️&lt;/p&gt;

&lt;p&gt;El nombre que le demos a esta interfaz debe de ser el mismo que le daremos en Android, si no habra discordancia entre plataformas. Yo lo llamaré &lt;em&gt;SAMPLE_MODULE&lt;/em&gt; como ejemplo.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9viorfxb7q8narky2tlx.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9viorfxb7q8narky2tlx.png" alt="Obj-c Header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego en nuestro archivo &lt;em&gt;SampleModule.m&lt;/em&gt; podemos hacer algo tal que así&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff1wocwv2qwwqcocyvali.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff1wocwv2qwwqcocyvali.png" alt="Obj-c Módulo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Android &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(No preocuparse si tenemos Hermes habilitado, no afecta)&lt;/p&gt;

&lt;p&gt;Podemos ir de varias maneras para poder usar nuestro módulo desde Android, aquí veremos una diferente a la de la documentación oficial de RN 😁 (de todas maneras en el repo dejo los archivos pertinentes para hacerlo de la manera oficial como en la doc.)&lt;/p&gt;

&lt;p&gt;Vamos a crearnos una nueva clase que en este caso la llamaré SampleModule para seguir en la misma tónica que en iOS, y nuestra clase se vería algo así:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8s38312284iklk04f4kz.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8s38312284iklk04f4kz.png" alt="Java Módulo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como en iOS decía, aquí tenemos que poner el mismo nombre que queremos que el Bridge exponga a la hora de obtener los métodos y para tener ambas plataformas con el mismo nombre por eso el &lt;em&gt;NAME = "SAMPLE_MODULE";&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;De la manera que lo haremos en este post ya no haría falta crear la clase Package, haremos esto en su lugar, nos vamos a la clase &lt;em&gt;MainApplication&lt;/em&gt; y en &lt;em&gt;getPackages&lt;/em&gt; añadiremos esto: (estoy usando la versión &lt;em&gt;0.61.5&lt;/em&gt; de RN)&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1qhq2bi0hit95936l0ow.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1qhq2bi0hit95936l0ow.png" alt="Java LazyModule"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Parece que hay mucha magia ahora mismo, pero os dejaré como siempre abajo links de interés para poder comprender todo esto de manera más amplia y que no se haga tan pesado este post también)&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript / TypeScript
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxt0d6knxwjqaff9z264r.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxt0d6knxwjqaff9z264r.png" alt="Go-Ts"&gt;&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flzwl7pqrh3ionwdcgfm6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flzwl7pqrh3ionwdcgfm6.gif" alt="Android-gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hasta ahora y todavía se sigue haciendo así las llamadas de los módulos nativos en RN, pero aquí hemos venido a jugar e ir un poco más allá de lo normal y nos adelantaremos en el tiempo, os mostraré como olvidarnos del bridge y todos sus beneficios que eso conlleva(o no 🙃).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;actualmente react-native funciona así&lt;/em&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%2Fformidable.com%2Fuploads%2Fold-diagram-full.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%2Fformidable.com%2Fuploads%2Fold-diagram-full.png" alt="RN ARCH"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/facebook/react-native/commit/060664fd3d9331f062696e68179bac9cd4544a06" rel="noopener noreferrer"&gt;https://github.com/facebook/react-native/commit/060664fd3d9331f062696e68179bac9cd4544a06&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://blog.nparashuram.com/2019/04/lazy-native-modules-react-native-android.html" rel="noopener noreferrer"&gt;http://blog.nparashuram.com/2019/04/lazy-native-modules-react-native-android.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://facebook.github.io/react-native/docs/native-modules-android" rel="noopener noreferrer"&gt;https://facebook.github.io/react-native/docs/native-modules-android&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://facebook.github.io/react-native/docs/native-modules-ios" rel="noopener noreferrer"&gt;https://facebook.github.io/react-native/docs/native-modules-ios&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>reactnative</category>
      <category>go</category>
      <category>crossplatform</category>
    </item>
    <item>
      <title>Módulos nativos para React-Native con Go (2/4)</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Mon, 25 Nov 2019 13:01:10 +0000</pubDate>
      <link>https://forem.com/x0s3/modulos-nativos-para-react-native-con-go-2-4-jjk</link>
      <guid>https://forem.com/x0s3/modulos-nativos-para-react-native-con-go-2-4-jjk</guid>
      <description>&lt;h1&gt;
  
  
  Creación del primer módulo con Go
&lt;/h1&gt;

&lt;p&gt;Pues ya estamos aquí, en esta segunda parte de esta serie de posts tan interesantes 🤥&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/37QVh74uQ5qeBOh0UF/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/37QVh74uQ5qeBOh0UF/giphy.gif" alt="HERE WE GO!!!"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(el gif introductorio que no falte)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Haremos algo rápido y sencillo para toda la familia, una función que la llamaremos de manera síncrona y otra de manera asíncrona para tener ambos casos contemplados (esta serie de posts no trata de realizar un módulo de dificultad avanzada ya que no es lo que toca ahora mismo).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;código del módulo que usaremos(sumar en js es muy complicado 🌚):&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fopfjlk173mdvt5ea6pyp.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fopfjlk173mdvt5ea6pyp.png" alt="Go module sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;tests (super exhaustivos oiga 🧐):&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fddyurw3yl9bd86i6y3n7.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fddyurw3yl9bd86i6y3n7.png" alt="Go test module sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cosas a tener en cuenta, tenemos restricción de tipos si vamos de esta manera(parte 3 bridge) ya que solo nos permite jugar con estos actualmente:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft422ch0lqyj111mzdshz.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft422ch0lqyj111mzdshz.png" alt="Restricted types"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tips/Consejitos de la abuela:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Si compiláis y luego no os aparece en vuestro módulo la función que estabais esperando obtener probablemente sea por problemas de tipado en el return de la función, así que "caution" con esto!! ⚠️⚠️ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Si os encontráis en una encrucijada y si o si debéis pasar algo que no esté soportado podéis hacer un stringify o pasarlo a un array de bytes el resultado final, luego acordaos de revertir el cambio en cada plataforma! (algo es algo 🤷‍♂️)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/TjoryRxEwh3bVr4M54/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/TjoryRxEwh3bVr4M54/giphy.gif" alt="A mi me ha pasao'!!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez tengamos nuestro código bien "testeadito" y queramos compilar ya todo esto, haremos uso del paquete que nos proporciona Golang "gomobile" así que si no lo tienes instalado, a qué esperas!?&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;go get golang.org/x/mobile/cmd/gomobile
&lt;span class="nv"&gt;$ &lt;/span&gt;gomobile init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Que lo queremos compilar para Android? mú' fácil!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gomobile &lt;span class="nb"&gt;bind&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;-target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;android &lt;span class="nv"&gt;$YOUR_FILE_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Que lo queremos compilar para iOS? mú' fácil también!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gomobile &lt;span class="nb"&gt;bind&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;-target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ios &lt;span class="nv"&gt;$YOUR_FILE_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;[-x -v]: vienen bien para hacer un seguimiento de como esta yendo el proceso de compilación, básicamente -x nos muestra que comandos realiza y -v pues de verbose, ya sabéis, que te lo muestra todo por la consola (ni la RAE con esta definición).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;$YOUR_FILE_PATH: fichero de entrada (el compilador ya se encargará de buscar las referencias de otros archivos o librerías que estemos usando), si tenéis problemas compilando esto recomiendo que lo metáis en la "carpetita" &lt;em&gt;&lt;em&gt;~go/src/github.com/NOMBRE_DE_TU_PAQUETE/NOMBRE_DEL_MAIN&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una vez ejecutado estos comandos (si no tienes mac solo puedes hacerlo para Android, o comprarte un mac y seguir la serie desde él, solo son 3mil eurillos de nada!!) tendremos en nuestra carpeta 3 nuevos archivos:&lt;/p&gt;

&lt;p&gt;Android:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/**/.aar&lt;/li&gt;
&lt;li&gt;/**/-sources.jar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;iOS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/**/.framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora viene la parte divertida, que es incluir los SDK's en sus correspondientes plataformas&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/y5yzypjVc9u3S/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/y5yzypjVc9u3S/giphy.gif" alt="Aguita lo que se nos viene"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(si solo te interesa la parte de Android, llévame allí)&lt;/p&gt;

&lt;h1&gt;
  
  
  iOS
&lt;/h1&gt;

&lt;p&gt;Abrimos nuestro gran amigo XCode y seleccionamos nuestro proyecto (.xcworkspace) o desde nuestro proyecto en RN&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open &lt;span class="nv"&gt;$path_de_tu_&lt;/span&gt;.xcworkspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para iOS es mucho mas sencillo que Android, hay menos pasos a realizar para poder vincular el módulo a nuestro proyecto&lt;/p&gt;

&lt;p&gt;Arrastramos nuestro archivo &lt;em&gt;.framework&lt;/em&gt; a nuestro proyecto, siempre dentro del proyecto!&lt;/p&gt;

&lt;p&gt;Automáticamente se nos vinculara el path con el que utiliza para compilar y hacer build, así que no nos debemos de preocupar de añadir la ruta manualmente (puede llegar a ser una odisea este tipo de tareas 🥵).&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbao8q3xg8hdnwyg9eqse.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbao8q3xg8hdnwyg9eqse.png" alt="iOS d&amp;amp;d framework"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Android &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;(Voy a usar Android-Studio para esto)&lt;/p&gt;

&lt;p&gt;Abrimos el proyecto android que tenemos en nuestro proyecto de RN y nos vamos directos a: &lt;em&gt;File &amp;gt; New &amp;gt; New Module...&lt;/em&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjbjyqq5maafqtszztyne.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjbjyqq5maafqtszztyne.png" alt="New android module"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se nos abrirá esta nueva ventana y seleccionamos &lt;em&gt;Import .JAR/.AAR Package&lt;/em&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F519ysevoug9x6oic5t8i.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F519ysevoug9x6oic5t8i.png" alt="Import JAR/AAR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Habrá que hacer esto 2 veces para importar ambos archivos&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx0cfgkwygppsz16ji2cc.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx0cfgkwygppsz16ji2cc.png" alt="JARAAR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez los tengamos importados ambos, nos vamos a: &lt;em&gt;File &amp;gt; Project Structure... &amp;gt; Modules &amp;gt; app &amp;gt; Dependencies &amp;gt; Add Module dependency&lt;/em&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzq8c4dwucbh8jih8kx9l.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzq8c4dwucbh8jih8kx9l.png" alt="Importar al proyecto el sdk"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos debería de salir ambos archivos importados, los seleccionamos y OK.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fip2003i8p88gprru2vuy.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fip2003i8p88gprru2vuy.png" alt="Ya casi tenemos Android vava!!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se nos sincronizará el proyecto y ya tendremos añadido el módulo en nuestro proyecto y listo para empezar con la parte de RN en la parte 3 ✌️&lt;/p&gt;

&lt;h2&gt;
  
  
  Y hasta aquí este capítulo 2, bastante turra por hoy
&lt;/h2&gt;

&lt;p&gt;Si has llegado hasta aquí y quieres dejar tu opinión sobre algo, tienes alguna duda o tienes problemas no dudes en hacérmelo saber!!&lt;/p&gt;

&lt;p&gt;links de referencia: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://godoc.org/golang.org/x/mobile/cmd/gomobile" rel="noopener noreferrer"&gt;https://godoc.org/golang.org/x/mobile/cmd/gomobile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://godoc.org/golang.org/x/mobile/cmd/gobind" rel="noopener noreferrer"&gt;https://godoc.org/golang.org/x/mobile/cmd/gobind&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/golang/go/wiki/Mobile#sdk-applications-and-generating-bindings" rel="noopener noreferrer"&gt;https://github.com/golang/go/wiki/Mobile#sdk-applications-and-generating-bindings&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nos vemos en la próxima entrega!!! 🥰
&lt;/h2&gt;

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

</description>
      <category>reactnative</category>
      <category>go</category>
      <category>crossplatform</category>
    </item>
    <item>
      <title>Módulos nativos para React-Native con Go (1/4)</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Thu, 21 Nov 2019 13:17:25 +0000</pubDate>
      <link>https://forem.com/x0s3/modulos-nativos-para-react-native-con-go-1-4-51gb</link>
      <guid>https://forem.com/x0s3/modulos-nativos-para-react-native-con-go-1-4-51gb</guid>
      <description>&lt;p&gt;&lt;a href="https://i.giphy.com/media/l0ExuiqMllbZywd8s/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l0ExuiqMllbZywd8s/giphy.gif" alt="I'm back boiz"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pues sí gente, he vuelto!&lt;/p&gt;

&lt;p&gt;Tenía ya ganas de volver a escribir algún post y este tema la verdad que me gustaría compartirlo con todos vosotros 😄&lt;/p&gt;

&lt;p&gt;La intención de esta serie de posts es ir de "0 to hero" en el desarrollo de módulos nativos y explicar un poco sobre el futuro de los módulos nativos de RN 🤓 &lt;/p&gt;

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

&lt;p&gt;La idea principal es separar por partes cada paso y digerir poco a poco todo sin que sea un tocho que ni Los Pilares de la Tierra:&lt;/p&gt;

&lt;h2&gt;
  
  
  Contenido previsto
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Toma de contacto y motivación&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/x0s3/modulos-nativos-para-react-native-con-go-2-4-jjk"&gt;Creación del primer módulo con Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unificar y llamar desde RN nuestro primer módulo, bridge(&lt;a href="https://dev.to/x0s3/modulos-nativos-para-react-native-con-go-3-4-40o7"&gt;https://dev.to/x0s3/modulos-nativos-para-react-native-con-go-3-4-40o7&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Unificar y llamar desde RN nuestro primer módulo (PARTE 4 JSI/TurboModules 🙄 WIP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sin más preámbulos 'amos al lío.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Toma de contacto y motivación &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;En esta introducción al gran camino del desarrollo de módulos para RN con Go, voy a dar bajo mi punta de vista las &lt;strong&gt;ventajas&lt;/strong&gt; que tiene:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compatibilidad con Android y iOS con el mismo código base&lt;/li&gt;
&lt;li&gt;Mucho mas sencillo que C++&lt;/li&gt;
&lt;li&gt;Ahorras tiempo desarrollando la misma funcionalidad&lt;/li&gt;
&lt;li&gt;Portabilidad a otras plataformas/entornos tales como Node.js o WASM 😜&lt;/li&gt;
&lt;li&gt;Ser capaces de reutilizar ese módulo para futuras apps con diferentes frameworks como Flutter, NativeScript, etc.&lt;/li&gt;
&lt;li&gt;Dar la bienvenida a las librerías de Go ya que podremos usarlas 🤩&lt;/li&gt;
&lt;li&gt;Foco de errores y tests en un único código fuente&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por desgracia no todo son ventajas también hay que mencionar las &lt;strong&gt;desventajas&lt;/strong&gt; o los pequeños problemas que puedes encontrar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actualmente la compatibilidad de tipos entre Go y Java/Objc no es muy amplia aún (ya explicaré en otro post o quizás en la parte 4 como podemos llegar a solventar este "problemilla")&lt;/li&gt;
&lt;li&gt;En Android tendremos que pasar por un nuevo bridge (NDK)&lt;/li&gt;
&lt;li&gt;Añadimos complejidad al proyecto&lt;/li&gt;
&lt;li&gt;El tema debug quizás se hace algo mas complicado de lo normal&lt;/li&gt;
&lt;li&gt;Tenemos que saber Go&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y ahora os preguntaréis ¿Qué tiene que ver esto con React-Native?&lt;br&gt;
Pues nada la verdad, pero si que nos podemos beneficiar y se podría decir que podemos desarrollar nuestra app ¿x4 de rápido? 🤔&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/lCbSAbRrFEfkY/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/lCbSAbRrFEfkY/giphy.gif" alt="FAST AND FURIOUS RN!!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Básicamente nos ahorramos el tener que aprender Objc o Java (o ambos) para poder llegar a tener nuestras apps a la par en tema de funcionalidades nativas, ya sean algoritmos complejos que requieran alto rendimiento, compartir lógica de negocio o simplemente queremos beneficiarnos de alguna librería ya creada con Go.&lt;/p&gt;

&lt;p&gt;La verdad que estoy bastante contento y sorprendido lo rápido que se puede llegar a realizar las cosas haciendo uso de Go con RN, sin ir más lejos tengo por aquí una app que las vistas son RN y todo lo demás funciona bajo un módulo de Go (la verdad que me he quitado un peso de encima al no tener que programar en Objc 😂) &lt;a href="https://github.com/x0s3/itbooks"&gt;Repo ItBooks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creo que lo podemos ir dejando por aquí de momento, una breve chapa, siento que en este post solo sea soltar "rollo-rollo" pero era algo necesario, los próximos serán mejores!!&lt;/p&gt;

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

</description>
      <category>reactnative</category>
      <category>go</category>
      <category>crossplatform</category>
    </item>
    <item>
      <title>Vaya el componente no existe para React-Native y no tenemos tiempo de desarrollarlo ¿qué hacemos?(Android parte I)</title>
      <dc:creator>x0s3</dc:creator>
      <pubDate>Sun, 07 Apr 2019 11:14:59 +0000</pubDate>
      <link>https://forem.com/x0s3/vaya-el-componente-no-existe-para-react-native-y-no-tenemos-tiempo-de-desarrollarlo-que-hacemos-android-parte-i-32df</link>
      <guid>https://forem.com/x0s3/vaya-el-componente-no-existe-para-react-native-y-no-tenemos-tiempo-de-desarrollarlo-que-hacemos-android-parte-i-32df</guid>
      <description>&lt;p&gt;¡Buenas lector 🖖! Primero de todo gracias por hacer click en mi primer post, confío en que sea de tu agrado y sea de utilidad lo explicado aquí.&lt;/p&gt;

&lt;p&gt;A quién no le ha pasado que desarrollando apps con React-Native no ha encontrado ese componente en &lt;a href="https://js.coach/" rel="noopener noreferrer"&gt;JS Coach&lt;/a&gt; que justo necesitaba para su proyecto y no tiene tiempo de desarrollarlo él mismo? (aquí servidor 🙋🏻‍♂️)&lt;/p&gt;

&lt;p&gt;Una de las cosas que más me costó de entender en RN es que no todo se lo tenemos que delegar a la parte de Javascript, la ventaja de usar este framework es que podemos irnos al mundo nativo y traernos lo que queramos!&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%2Fmedia1.giphy.com%2Fmedia%2F3ohzdIuqJoo8QdKlnW%2Fgiphy.gif%3Fcid%3D790b76115ca90e6a412e4b674d9705f5" 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%2Fmedia1.giphy.com%2Fmedia%2F3ohzdIuqJoo8QdKlnW%2Fgiphy.gif%3Fcid%3D790b76115ca90e6a412e4b674d9705f5" alt="Awesome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Así que para esta primera parte y primer post, nos iremos al mundo nativo y nos traeremos un componente de &lt;a href="https://android-arsenal.com" rel="noopener noreferrer"&gt;Android Arsenal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;No será el típico ejemplo de hacer un botón en Android porque para eso ya tenemos lo que nos trae el framework, para ir haciendo una toma de contacto sobre todo lo que podemos traernos del otro mundo, empezaremos trayendo un componente sencillo ya que en nuestro proyecto nos han pedido con urgencia que implementemos un rasca y gana.Que no cunda el pánico porque esto lo solucionamos rápidamente.&lt;/p&gt;

&lt;p&gt;Primero de todo añadiremos una librería a nuestro proyecto que nos facilitará la creación de los ficheros nativos para ello:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react-native-create-bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez instalado lo llamamos de esta manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;react-native new-module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y se nos mostrará por consola una serie de opciones a elegir dependiendo de lo que queramos crear, para nuestro caso será un componente nativo y escribiremos en Java lo que haya que escribir.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe9b1pty291u8jb216kbq.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe9b1pty291u8jb216kbq.png" alt="New-Module"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez hecho esto tendremos en nuestro directorio un archivo .js con el nombre que le hayamos dado a nuestro componente(en nuestro caso NativeScratchCard.js), si nos vamos a nuestro directorio Android podemos ver que la librería nos ha generado un package con el nombre "nativescratchcard" donde tenemos 2 archivos Java.&lt;/p&gt;

&lt;p&gt;Pues bien antes de hacer nada más, importamos la librería nativa que nos salvará de este aprieto, en nuestro caso usaremos esta misma &lt;a href="https://android-arsenal.com/details/1/7597" rel="noopener noreferrer"&gt;Scratch Card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(sí, lo sé, a partir de ahora podremos usar casi cualquier cosa que queramos ya hecha jeje) &lt;a href="https://i.giphy.com/media/TlK63Eu7Dwok2j8TgfS/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/TlK63Eu7Dwok2j8TgfS/giphy.gif" alt="ITS FREE"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Añadimos la dependencia a nuestra app, sincronizamos y listo ya podemos empezar a traer este componente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;codeshuffle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scratchcardlayout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;ScratchCardLayout:&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;fileTree&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;dir:&lt;/span&gt; &lt;span class="s"&gt;"libs"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;include:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"*.jar"&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s"&gt;"com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s"&gt;"com.facebook.react:react-native:+"&lt;/span&gt;  &lt;span class="c1"&gt;// From node_modules&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos dirigimos a &lt;strong&gt;&lt;em&gt;NativeScratchCardManager.java&lt;/em&gt;&lt;/strong&gt; y haremos unos cuantos cambios en el código generado, el primero de todos es cambiar el tipo de la clase de la que extendemos, con esto le decimos a nuestro querido rn que vamos a traernos el componente ScratchCardLayout y no una simple View.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;View -&amp;gt; ScratchCardLayout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cambiaremos el método createViewInstance también de esta forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ScratchCardLayout&lt;/span&gt; &lt;span class="nf"&gt;createViewInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ThemedReactContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REACT_CLASS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"createViewInstance"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ScratchCardLayout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;leyendo la librería nativa podemos ver que se nos expone varios métodos para poder modificar nuestra ScratchCard, nosotros expondremos 3 propiedades para poder usarlas en nuestro componente en rn: el tamaño del pincel, el porcentaje para acabar y si queremos que esté habilitado o no el componente.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkzmgiqg7e6qzbojgc3dp.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkzmgiqg7e6qzbojgc3dp.png" alt="React Props"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¡¡Ánimo que ya casi estamos!&lt;a href="https://i.giphy.com/media/ToMjGpz81S7usvTIM8w/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ToMjGpz81S7usvTIM8w/giphy.gif" alt="Ansiosos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora pensándolo bien, nos damos cuenta que queremos exponer nuestro componente escrito en Javascript dentro de este componente nativo y vaya...parece que no hay ningún tutorial explicando como conseguir esto 😱lamentablemente si queremos traer cosas del lado nativo hay que saber o al menos tener nociones sobre Android, pero no pasa nada porque aquí mostraré como hacerlo en este primer post de manera sencilla(y agradecer a &lt;a href="https://yogalayout.com/" rel="noopener noreferrer"&gt;Yoga&lt;/a&gt; que esto sea posible).&lt;/p&gt;

&lt;p&gt;Para ello cambiaremos la clase de la que extiende nuestra clase componente&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SimpleViewManager -&amp;gt; ViewGroupManager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;y sobre-escribiremos el método &lt;strong&gt;addView&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ScratchCardLayout&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REACT_CLASS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"addView"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ya solo nos queda exponer los eventos del componente nativo a nuestro componente en js y ya habremos acabado de tocar Java.&lt;/p&gt;

&lt;p&gt;Para no hacer demasiado extenso el post esta parte está explicada muy bien en la documentación oficial de &lt;a href="https://facebook.github.io/react-native/docs/native-components-android#events" rel="noopener noreferrer"&gt;RN&lt;/a&gt; (tranquilos, también adjunto captura de nuestro código)&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fybfun0i6ivqomnsmqxbp.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fybfun0i6ivqomnsmqxbp.png" alt="Native Events"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos volvemos a nuestro método &lt;strong&gt;createViewInstance&lt;/strong&gt; y lo modificamos para que nos exponga los eventos nativos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ScratchCardLayout&lt;/span&gt; &lt;span class="nf"&gt;createViewInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NonNull&lt;/span&gt; &lt;span class="nc"&gt;ThemedReactContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REACT_CLASS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"createViewInstance"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;ScratchCardLayout&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ScratchCardLayout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;onReceiveNativeEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setScratchDrawable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResources&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getDrawable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;drawable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rn_image_scratch&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y pues ya estaríamos o no...para poder exponerlo y usarlo tenemos que añadir el package en nuestro MainApplication&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactPackage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getPackages&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactPackage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MainReactPackage&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NativeScratchCardPackage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;y ahora ya si que estamos listos para pasarnos a escribir un poco de Javascript.&lt;/p&gt;

&lt;p&gt;Modificaremos nuestro archivo generado anteriormente para que sea como este:&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="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;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;requireNativeComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&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;ScratchCardView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;requireNativeComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NativeScratchCard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ScratchCardComponent&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&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="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;started&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;onChange&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;STARTED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;progress&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;onChange&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;PROGRESS&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;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;finished&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;onChange&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;FINISHED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScratchCardView&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&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="nx"&gt;style&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="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onChange&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;ScratchCardComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;la propiedad onChange hace referencia a topChange en nuestro código nativo, podéis leer más sobre eso en el link que he dejado más arriba sobre los eventos.&lt;/p&gt;

&lt;p&gt;Y nuestro archivo App.tsx podemos dejarlo tal que así:&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="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;started&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;progress&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;STARTED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;started&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FINISHED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PROGRESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;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="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;Scratch&lt;/span&gt; &lt;span class="nx"&gt;started&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;started&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yep :)&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;Nop :(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;Is&lt;/span&gt; &lt;span class="nx"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;finished&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yep :)&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;Nop :(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;Current&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScratchCard&lt;/span&gt;
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="nx"&gt;finishAt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;brushWidth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;welcome&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;HEY&lt;/span&gt; &lt;span class="nx"&gt;IM&lt;/span&gt; &lt;span class="nx"&gt;YOUR&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt; &lt;span class="nx"&gt;COMPONENT&lt;/span&gt;&lt;span class="o"&gt;!!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ScratchCard&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&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;Y si todo ha ido bien una vez compilamos la app nos debería de aparecer ya el componente&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgjimjf5d8xr5zpbv4x2k.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgjimjf5d8xr5zpbv4x2k.png" alt="RN Component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y funcionando correctamente&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5r217jxhr0q0u7dcbelx.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5r217jxhr0q0u7dcbelx.png" alt="RN Component 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Funciona todo y desde ahora podremos usar componentes tanto nativos como de js!!&lt;/p&gt;

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

&lt;p&gt;Gracias si has llegado hasta aquí, espero que no se te haya hecho muy pesado y ojalá hayas aprendido algo nuevo con este post, cualquier duda o sugerencia no dudes en hacérmelo saber!!&lt;/p&gt;

&lt;p&gt;Link al repo de github: &lt;a href="https://github.com/x0s3/scratchNativeCard" rel="noopener noreferrer"&gt;Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>android</category>
    </item>
  </channel>
</rss>
