
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet href="https://jolicode.com/feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="fr-FR">
    <id>https://jolicode.com/blog</id>
    <link type="text/html" rel="alternate" href="https://jolicode.com/blog"/>
    <link type="application/rss+xml" rel="self" href="https://jolicode.com/feeds/blog/tag/react.atom" />

            <title>JoliCode blog - derniers articles au sujet de "react"</title>
        <updated>2026-05-12T20:29:36+02:00</updated>    <entry>
        <id>https://jolicode.com/blog/react-advanced-london-depuis-nos-canapes</id>
        <published>2022-11-15T13:42:00+01:00</published>
        <updated>2022-11-15T13:42:00+01:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/react-advanced-london-depuis-nos-canapes"/>
        <title>React Advanced London (depuis nos canapés)</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="javascript" />            <category term="conférence" />            <category term="react" />            <category term="react-advanced-london" />        <summary><![CDATA[Nous avons eu la chance de pouvoir assister à la conférence React Advanced London en remote, voici ce que nous en avons retenu de ces deux jours intenses !
React internals
C’était le slogan de la conférence…]]></summary>
        <content type="html">
            &lt;p&gt;Nous avons eu la chance de pouvoir assister à la conférence React Advanced London en remote, voici ce que nous en avons retenu de ces deux jours intenses !&lt;/p&gt;
&lt;h2&gt;React internals&lt;/h2&gt;
&lt;p&gt;C’était le slogan de la conférence cette année : &amp;quot;We will be diving deep&amp;quot; et nous n’avons pas été déçues. Plusieurs conférenciers nous ont parlé de ce qui se  passe réellement sous le capot quand on utilise React.&lt;/p&gt;
&lt;h3&gt;&amp;quot;Understanding React’s Fiber Architecture&amp;quot; - Tejas Kumar&lt;/h3&gt;
&lt;p&gt;Tejas Kumar nous a expliqué en plongeant dans le code le fonctionnement de React Fiber, le nouvel algorithme de réconciliation, introduit dans React 16 pour rendre notre librairie préférée plus rapide et performante. Résumé grossièrement, les Fiber sont une sorte de structure de données, que React conserve pour garder une trace de ce qui se passe dans nos applications. Elles ont donc une durée de vie longue par opposition aux Element qui eux sont éphémères. Fiber Reconcilier, l’algorithme de réconciliation, maintient en permanence deux arbres, le courant et le &amp;quot;work in progress&amp;quot;, boucle sur tous nos composants en partant du haut pour détecter ce qui a changé, ajoute des flags sur ce qui doit être mis à jour, ce qui changé, etc. puis bascule sur le deuxième arbre qui devient alors la nouvelle source de vérité. Il réconcilie ensuite cet arbre avec l’environnement hôte (navigateur, application mobile) pour mettre à jour l’UI. Cette nouvelle architecture permet ainsi un rendu incrémentiel de nos applications.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-understanding-react-fiber.5d9b5087.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-understanding-react-fiber.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 181)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-understanding-react-fiber.png&quot; alt=&quot;Les deux arbres créés par React Fiber&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Ainsi décortiqué, le fonctionnement interne de React ne semble plus si complexe. Une plongée  passionnante à voir dès qu’elle sera disponible. En attendant nous vous recommandons sa conférence &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=f2mMOiCSj5c&amp;amp;ab_channel=CodingTech&quot;&gt;Deconstructing React&lt;/a&gt; si vous n’avez pas encore eu l’occasion de la voir).&lt;/p&gt;
&lt;h3&gt;Deep diving on concurrent React - Matheus Albuquerque&lt;/h3&gt;
&lt;p&gt;Durant l’exécution de certaines tâches trop longues, le thread principal de JavaScript se retrouve bloqué. Ces blocages sont gênants, d’autant plus pour les utilisateurs sur mobile pour qui ils peuvent durer 7 à 12 fois plus longtemps. Il s’agit d’un problème réel, qui en plus d’être désagréable pour vos utilisateurs a également un fort impact sur le taux de conversion de vos applications. Pour éviter de bloquer le thread principal, il existe trois stratégies principales : le parallélisme, l’exécution concurrente et le scheduling (planification).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-deep-diving-in-concurrent-react.768e5faf.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-deep-diving-in-concurrent-react.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 274)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-deep-diving-in-concurrent-react.png&quot; alt=&quot;Trois stratégies pour ne pas bloquer le thread principal&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;React 18 introduit des nouveautés intéressantes sur le sujet. Nous pourrons par exemple traiter plus efficacement les gros volumes de données en priorisant les render (grâce à l’API &lt;strong&gt;startTransition&lt;/strong&gt;), limiter les renders inutiles avec le hook &lt;strong&gt;useSyncExternalStore&lt;/strong&gt;, prioriser le chargement des zones d’interaction pour diminuer le first input delay (hydration sélective) ou encore monitorer les performances des applications grâce au profiler qui sera capable d’indiquer quelles opérations trop gourmandes pourraient bénéficier de &lt;strong&gt;startTransition&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Matheus a conclu avec quelques mises en garde, le scheduling n’implique pas forcément de meilleures performances et il n’y a pas de solution miracle. Il faut identifier les métriques qui sont fondamentales pour nos applications et partir de là. Enfin il a brièvement évoqué le futur de React : un composant built-in &lt;code&gt;&amp;lt;Cache&amp;gt;&lt;/code&gt; pour la récupération de données, à utiliser avec &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Composition&lt;/h2&gt;
&lt;h3&gt;Code Crimes For Good Component API - Siddharth Kshetrapal&lt;/h3&gt;
&lt;p&gt;Quelles sont les qualités d&#039;une bonne interface utilisateur ? Elle doit être intuitive, accessible et cohérente. Il en va de même pour l’API de nos composants. Siddharth Kshetrapal nous a expliqué à travers plusieurs exemples comment il fait en sorte, quitte à utiliser quelques hacks, que ses APIs de composants respectent ce contrat.&lt;/p&gt;
&lt;p&gt;La leçon que nous en retenons est le fil rouge de la conférence :
&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-code-crimes-for-good-component-api.41df8772.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-code-crimes-for-good-component-api.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 375px; ; aspect-ratio: calc(375 / 91)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-code-crimes-for-good-component-api.png&quot; alt=&quot;Hacks that make the code easier to read and author... are okay&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Ce qui donne en français : les hacks qui rendent le code plus facile à lire et à modifier, et qui aident les développeurs à faire du bon travail rapidement, en respectant des contraintes raisonnables du système, sont ok.&lt;/p&gt;
&lt;h3&gt;React Slots: a New Way of Composition - Neo Nie&lt;/h3&gt;
&lt;p&gt;Qui ne s’est pas retrouvé un jour à devoir maintenir un composant &lt;strong&gt;TextInput&lt;/strong&gt; avec plus d’une quinzaine de props, ou un composant &lt;strong&gt;Message&lt;/strong&gt; qui gère une dizaine de cas d’usages différents ? Neo Nie a fait un état des lieux des problèmes inhérents à la composition avec React que nous avons tous rencontrés au moins une fois dans notre carrière.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-react-slots.14e8b288.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-react-slots.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 273)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-react-slots.png&quot; alt=&quot;Exemple de composants avec trop de props&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Ces différents problèmes l’ont amené à s’intéresser aux différents patterns de composition qui existent, et notamment à l’utilisation dans React du pattern &lt;strong&gt;Slots&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-react-slots-2.28428767.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-react-slots-2.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 108)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-react-slots-2.png&quot; alt=&quot;Définition en anglais du pattern Slots&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Ce pattern permet de définir des sortes de placeholder, identifiés par un attribut unique, dans un template et qui peuvent être utilisés ensuite pour définir n’importe quel contenu. Vous avez probablement déjà utilisé ce pattern sans même le savoir, à chaque fois que vous utilisez des props nommées pour rendre des parties d’un composant.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; TextInput&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; ({ &lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; }) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; className&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;form-group&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; className&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;form-label&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&amp;#x3C;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; type&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; name&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;error &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; className&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;form-error&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ici, &lt;code&gt;error&lt;/code&gt; et &lt;code&gt;label&lt;/code&gt; sont des slots.
Pour mettre en place les slots dans ses projets, Neo a créé la librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/nihgwu/create-slots&quot;&gt;create-slots&lt;/a&gt; qui s’utilise en définissant des slots et des hosts (un composant qui a un layout formé de plusieurs slots).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-react-slots-3.a5258a2e.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-react-slots-3.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 511)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-react-slots-3.png&quot; alt=&quot;Utilisation de react-slots dans le code&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;La librairie est encore relativement jeune mais le concept semble prometteur. À suivre !&lt;/p&gt;
&lt;h2&gt;Accessibilité&lt;/h2&gt;
&lt;h3&gt;Creating an Accessible Web Together in 5 Simple Steps - Shruti Kapoor&lt;/h3&gt;
&lt;p&gt;Shruti Kapoor nous a présenté ses astuces pour un Web plus accessible. Après avoir rappelé l’importance de l’accessibilité, elle nous offre un moyen mnémotechnique avec l’acronyme STARK pour se souvenir de 5 choses à toujours garder en mémoire :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S&lt;/strong&gt; pour Semantic HTML : utiliser les balises qui correspondent à ce que vous en faites (button pour des actions, &lt;code&gt;a&lt;/code&gt; pour des liens, mais aussi nav, header, main…) et &lt;strong&gt;bien&lt;/strong&gt; les utiliser (une balise &lt;code&gt;a&lt;/code&gt; a toujours un &lt;code&gt;href&lt;/code&gt;, &lt;code&gt;img&lt;/code&gt; a un &lt;code&gt;alt&lt;/code&gt;, ne pas créer de &amp;quot;faux&amp;quot; titres en CSS). Les lecteurs d’écrans risqueraient autrement de donner la mauvaise information à leurs utilisateurs. Utiliser les balises natives à bon escient vous offre donc une accessibilité à bas coût.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;T&lt;/strong&gt; pour tabindex : Il est important de définir un &lt;strong&gt;tab order&lt;/strong&gt; logique. Par ailleurs Shruti rappelle que le tabindex ne doit pas être supérieur à 0, pour ne pas perdre les lecteurs d’écran. Il est possible de débugger son &lt;strong&gt;tab order&lt;/strong&gt; avec Firefox par exemple.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt; pour Aria tags : &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;aria-described-by&lt;/code&gt;, &lt;code&gt;checked&lt;/code&gt;, &lt;code&gt;expanded&lt;/code&gt;, &lt;code&gt;haserrormessage&lt;/code&gt;, &lt;code&gt;aria-hidden&lt;/code&gt;… Nous ne les présentons plus et pourtant nous ne pensons pas toujours à les utiliser. Chez JoliCode, nous aimons aussi les utiliser dans notre CSS, ce qui permet de ne pas les oublier et de faire d’une pierre deux coups !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;R&lt;/strong&gt; pour &lt;strong&gt;Role&lt;/strong&gt; : attribut à utiliser dès lors que nous ne pouvons pas utiliser les balises natives qui correspondent à notre besoin&lt;/p&gt;
&lt;p&gt;Enfin &lt;strong&gt;K&lt;/strong&gt; pour Keyboard navigation &amp;amp; screen readers : il faut toujours s’assurer par exemple que le focus est visible à l&#039;écran. Shruti recommande de tester soi-même en utilisant seulement &lt;kbd&gt;tab&lt;/kbd&gt;, la barre d’&lt;kbd&gt;espace&lt;/kbd&gt;, &lt;kbd&gt;Enter&lt;/kbd&gt; et &lt;kbd&gt;Echap&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-creating-an-accessible-web.2a0e5ddc.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-creating-an-accessible-web.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 378)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-creating-an-accessible-web.png&quot; alt=&quot;Checklist d&#039;accessibilité&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Elle nous recommande ensuite quelques outils pour faire nos tests, les extensions navigateurs &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd&quot;&gt;aXe&lt;/a&gt; et &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://wave.webaim.org/extension/&quot;&gt;Wave&lt;/a&gt;, les outils intégrés à Firefox ou à Chrome, les outils au build comme &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/dequelabs/axe-core&quot;&gt;axe-core&lt;/a&gt; ou &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/jsx-eslint/eslint-plugin-jsx-a11y&quot;&gt;jsx-a11y&lt;/a&gt;, ou encore l’outil de CI &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://accesslint.com/&quot;&gt;accesslint&lt;/a&gt; pour identifier les soucis d&#039;accessibilité directement dans les PRs GitHub.&lt;/p&gt;
&lt;p&gt;N’hésitez pas également à tester la navigation clavier, les lecteurs d’écran, et les tests automatisés. Enfin rien ne vaut un test avec des utilisateurs réels.&lt;/p&gt;
&lt;p&gt;Nous pouvons même aller plus loin en proposant des raccourcis clavier pratiques pour l’édition, ou encore des focus trap dans certaines zones de l’application.&lt;/p&gt;
&lt;h2&gt;Tips et bonnes pratiques&lt;/h2&gt;
&lt;h3&gt;The Weird Things About React - Nik Graf&lt;/h3&gt;
&lt;p&gt;Cette conférence est l’occasion de souligner certaines bizarreries de React, connues ou moins connues, à commencer par les versions de React, passées brutalement de 0.14.7 à 15.0.0 (pour l’explication c’est &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://reactjs.org/blog/2016/02/19/new-versioning-scheme.html&quot;&gt;par ici&lt;/a&gt;), mais aussi de nous donner quelques protips pour utiliser React. Saviez-vous par exemple qu’il est possible d’utiliser la prop &lt;code&gt;key&lt;/code&gt; pour forcer un composant à être remonté ? On y apprend aussi qu’on peut utiliser la fonction &lt;code&gt;flushSync&lt;/code&gt; pour re-rendre de manière synchrone lorsque nous recevons une mise à jour de données (pas encore documenté mais discuté &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/react/issues/11527&quot;&gt;par exemple ici&lt;/a&gt;), que React 18 &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/reactwg/react-18/discussions/75&quot;&gt;autorise nos composants à renvoyer &lt;code&gt;undefined&lt;/code&gt;&lt;/a&gt; ou encore que les hooks &lt;strong&gt;peuvent&lt;/strong&gt; être utilisés conditionnellement, à condition d’ignorer le warning de React (mais c’est mal, ne faites pas ça chez vous). Il est également possible de tricher pour utiliser un export nommé avec React.lazy().&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-the-weird-things-about-react.be332932.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-the-weird-things-about-react.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 135)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-the-weird-things-about-react.png&quot; alt=&quot;Utilisation de React lazy avec un export nommé&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Le type &lt;code&gt;React.FunctionComponent&lt;/code&gt; (et son alias &lt;code&gt;React.FC&lt;/code&gt;) souvent décrié par les développeurs TypeScript pour sa prop children implicite, perd cette prop en React 18, ce qui veut dire que nous pouvons maintenant l’utiliser avec une prop children obligatoire.&lt;/p&gt;
&lt;p&gt;En conclusion de sa conférence, Nik nous a présenté &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/nikgraf/react-reduce-stress&quot;&gt;react-reduce-stress&lt;/a&gt;, une petite librairie qu’il a développé et qui permet de masquer certains warnings et erreurs de React comme le fameux warning sur l’ordre des hooks ou encore celui du mode strict de React 18 qui nous informe que les &lt;code&gt;useEffect&lt;/code&gt; seront exécutés 2 fois au premier rendu d’un composant. Nous ne pouvons que vous conseiller au passage de tester le mode strict de React 18 pour détecter les composants qui ne sont pas à jour et les effets de bord.&lt;/p&gt;
&lt;h3&gt;Using useEffect Effectively - David Khourshid&lt;/h3&gt;
&lt;p&gt;Dans cette très bonne conférence, David Khourshid nous réapprend à utiliser &lt;code&gt;useEffect&lt;/code&gt;, ou plutôt ce que nous devrions utiliser à la place et dans quelles situations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nous n’avons pas besoin de useEffect pour transformer de la donnée. Il vaut mieux utiliser un useMemo ou mieux, n’utiliser aucun hook et passer à useMemo seulement en cas de problème de performance avéré ;&lt;/li&gt;
&lt;li&gt;Pas de useEffect non plus pour communiquer avec le parent. Dans ce cas mieux vaut exécuter notre effet directement dans la gestion de l’évènement ;&lt;/li&gt;
&lt;li&gt;Pas de useEffect pour souscrire à un store externe. L’injustement méconnu &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore&quot;&gt;useSyncExternalStore&lt;/a&gt; est là pour ça ;&lt;/li&gt;
&lt;li&gt;Pas besoin de useEffect pour fetcher de la donnée. La librairie react-query dispose de hooks terriblement efficaces pour ça, avec Next.js on peut également utiliser useSWR() ou simplement use() avec du cache ;&lt;/li&gt;
&lt;li&gt;Initialiser un singleton global (configurer un client Axios, s’authentifier sur un store externe, etc) sera plus efficace sans useEffect, en-dehors du composant ;&lt;/li&gt;
&lt;li&gt;Enfin, n’utilisez pas useEffect pour gérer les actions de l’utilisateur. Il vaut bien mieux exécuter les effets dans les event handler directement. Nous pouvons par exemple utiliser une state machine :&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-using-useffect-effectively.9c115ac7.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-using-useffect-effectively.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 287)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-using-useffect-effectively.png&quot; alt=&quot;Exemple de state machine&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;De manière générale, &lt;code&gt;useEffect&lt;/code&gt; doit être utilisé pour les effets &amp;quot;d’activité&amp;quot;, pour la synchronisation. Pour les effets &amp;quot;d’action&amp;quot;  il est plus adapté (et souvent plus simple) de les mettre au plus près des événements qui les causent, ce qui implique souvent de ne pas utiliser &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Treat Your Users Right with Segmented Rendering - Eric Burel&lt;/h3&gt;
&lt;p&gt;Toutes nos applications rencontrent un jour des problématiques de personnalisation ou segmentation, que ce soit pour les adapter à différentes langues, à différents types d’utilisateurs (payants ou non), pour mettre en place de l’A/B testing, etc. C’est pourquoi il est nécessaire de pouvoir rendre du contenu adapté à l’utilisateur actuel. La plupart de nos frameworks JavaScript actuels proposent différents modes de rendu plus ou moins statiques pour améliorer les performances. Comment en tirer profit tout en évitant d’avoir des invités riches et des clients pauvres (bonnes performances seulement pour les utilisateurs non payants qui ne nécessitent pas de personnalisation) ?  Eric Burel nous propose une solution simple et facile à mettre en place. Dans l’exemple de Next.js, le contenu peut être rendu côté serveur, côté client ou dans un mode intermédiaire &amp;quot;static site generation&amp;quot;. Les deux premiers modes sont dynamiques mais lents, alors que le dernier est très performant, mais comme son nom l’indique il est statique.&lt;/p&gt;
&lt;p&gt;Une solution possible est d’utiliser des URLs avec des paramètres différents pour chaque segment mais cela pose de nombreux autres problèmes, le paramètre est visible par les utilisateurs, les URLs peuvent être changées à la main et elles peuvent vite devenir très longues.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-treat-your-users-right-with-segmented-rendering.e9d35657.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-treat-your-users-right-with-segmented-rendering.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 287)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-treat-your-users-right-with-segmented-rendering.png&quot; alt=&quot;Problèmes posés par la personnalisation dans les URLs&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;La deuxième solution est d’utiliser un serveur proxy qui lit un cookie (ou un header par exemple) et réécrit l’url. La réécriture n’étant pas une redirection, l’utilisateur ne peut ni voir ni modifier l’URL. Avec Next.js, le serveur proxy est un simple middleware.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-treat-your-users-right-with-segmented-rendering-2.6200cbe4.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-treat-your-users-right-with-segmented-rendering-2.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 297)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-treat-your-users-right-with-segmented-rendering-2.png&quot; alt=&quot;Exemple de serveur proxy avec Next.js&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Une bonne astuce à garder en mémoire pour tous vos problèmes de personnalisation.&lt;/p&gt;
&lt;h2&gt;Performances&lt;/h2&gt;
&lt;h3&gt;Automated Performance Regression Testing with Reassure - Michał Pierzchała&lt;/h3&gt;
&lt;p&gt;Michał part d’un constat auquel nous avons tous dû faire face un jour : les performances de nos applications tendent naturellement à se dégrader avec le temps et les développements successifs. Il est donc important de mettre en place des tests de non-régression des performances, au moins sur les parties qui risquent le plus d’impacter nos utilisateurs.&lt;/p&gt;
&lt;p&gt;En analysant la fréquence de chacune des principales causes des problèmes de performance, il lui est apparu assez clairement que la plupart des problèmes sont liés à JavaScript plutôt qu’à React ou à React Native.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-automated-performance-regression-resting-with-reassure.f165b04e.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-automated-performance-regression-resting-with-reassure.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 285)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-automated-performance-regression-resting-with-reassure.png&quot; alt=&quot;Causes principales des problèmes de performance avec React&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Ne trouvant pas de librairie de test adaptée à son besoin assez spécifique,  Michał a choisi de créer sa propre librairie : &lt;strong&gt;reassur&lt;/strong&gt;. Celle-ci a donc été conçue pour s’intégrer avec les librairies de tests existantes afin de tester les performances des render, en mesurant leur durée et leur nombre. Elle permet aussi de générer des rapports, et s&#039;intègre avec les CI les plus connues. Les tests de performance sont lancés sur la branche courante et sur la branche principale et les résultats sont comparés en utilisant l’analyse statistique.&lt;/p&gt;
&lt;p&gt;Écrire les tests est relativement simple, il suffit de copier un test fonctionnel et d’y ajouter quelques lignes de code.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-automated-performance-regression-resting-with-reassure-2.3472fcc5.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-automated-performance-regression-resting-with-reassure-2.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 284)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-automated-performance-regression-resting-with-reassure-2.png&quot; alt=&quot;Exemple d&#039;un test avec reassure&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-automated-performance-regression-resting-with-reassure-3.b915f18c.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-automated-performance-regression-resting-with-reassure-3.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 290)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-automated-performance-regression-resting-with-reassure-3.png&quot; alt=&quot;Résultat du test avec reassure&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;La présentation de la librairie était très convaincante, nous avons hâte de la tester chez nous !&lt;/p&gt;
&lt;h2&gt;TypeScript&lt;/h2&gt;
&lt;h3&gt;TypeScript and React: Secrets of a Happy Marriage  - Matt Pocock&lt;/h3&gt;
&lt;p&gt;Cette conférence nous a particulièrement intéressées. Matt Pocock expose certains des problèmes que tout utilisateur de TypeScript rencontre un jour et nous en donne une solution élégante. En voici quelques uns :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le typing dynamique, qui consiste à avoir une variable pouvant être soit un type A soit un type B, peut poser des problèmes lorsque l’on cherche à accéder à une propriété spécifique à un des deux types :&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-typescript-and-react.9c2f2239.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-typescript-and-react.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 302)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-typescript-and-react.png&quot; alt=&quot;Exemple de composant utilisant du typing dynamique&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;La solution est d’utiliser l’opérateur &lt;code&gt;in&lt;/code&gt;, par exemple &lt;code&gt;if (‘href’ in props)&lt;/code&gt; , TypeScript saura grâce à ce test que nos props sont d’un certain type.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deux props qui dépendent toutes les deux du même type, que nous ne pouvons pas connaître à l’avance, par exemple &lt;code&gt; row: unknow[]&lt;/code&gt; et &lt;code&gt;renderRow: (row: unknow) =&amp;gt; React.ReactNode&lt;/code&gt;. La solution ici est d’utiliser les types génériques. En plus, lorsque nous ne spécifions pas le type TRow, celui-ci sera inféré automatiquement par TypeScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-typescript-and-react-2.c7cd75e5.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-typescript-and-react-2.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 206)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-typescript-and-react-2.png&quot; alt=&quot;Exemple de types génériques&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Nous pouvons aussi utiliser &lt;code&gt;extends&lt;/code&gt; pour forcer certaines propriétés :&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-typescript-and-react-3.4aaa78ac.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-typescript-and-react-3.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 264)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-typescript-and-react-3.png&quot; alt=&quot;Exemple de type générique utilisant extends&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les types de React sont écrits et maintenus en dehors de la lib, dans &lt;code&gt;@types/react&lt;/code&gt; et ils peuvent parfois présenter de légères différences qui peuvent être ennuyantes. Par ailleurs certaines fonctions comme les hooks &lt;code&gt;useState&lt;/code&gt; et &lt;code&gt;useRef&lt;/code&gt; ont différents overloads, c’est-à-dire qu’ils ont plusieurs signatures et les types inférés par TypeScript dépendent de l’overload utilisé :&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-typescript-and-react-4.5e819b57.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-typescript-and-react-4.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 205)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-typescript-and-react-4.png&quot; alt=&quot;Exemple d&#039;utilisation de useRef pour un élément HTML&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2022/react-advanced-typescript-and-react-5.d3e6961e.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2022/react-advanced-typescript-and-react-5.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 512px; ; aspect-ratio: calc(512 / 201)&quot; src=&quot;https://jolicode.com//media/cache/content/2022/react-advanced-typescript-and-react-5.png&quot; alt=&quot;Différentes utilisations possibles de useRef&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Par ailleurs certains de ces comportements peuvent paraître incohérents, par exemple, ne pas fournir de valeur initiale pour useRef va inférer un type &lt;code&gt;number | undefined&lt;/code&gt;. Pour ne pas être perdu face à ces différences, la meilleure solution reste de bien comprendre le fonctionnement de ces fonctions, n’hésitez donc pas à aller jeter un oeil aux types !&lt;/p&gt;
&lt;h2&gt;L’expérience du remote&lt;/h2&gt;
&lt;p&gt;Regarder des conférences  depuis le confort de son canapé est certes appréciable, mais plusieurs aspects des conférences live nous ont toutefois un peu manqué. Assister à des conférences c’est aussi l’occasion de discuter avec d’autres développeurs de tous horizons, et même si les organisateurs avaient fait de leur mieux pour nous proposer différentes plateformes et réseaux, il reste plus difficile d’aller vers les autres en remote qu’en live.&lt;/p&gt;
&lt;p&gt;Concernant les conférences elles-mêmes, celles-ci étaient retransmises en décalé par rapport à la programmation live, du début d’après-midi jusqu’à assez tard dans la soirée, un point vraiment négatif pour les spectateurs qui ont des contraintes familiales par exemple. Il aurait probablement été plus judicieux de faire plusieurs streams en horaires décalés pour permettre à la majorité des timezones de suivre toutes les conférences. Heureusement, l’ensemble des conférences ainsi que les workshops  gratuits devraient être rendus disponibles en vidéo.&lt;/p&gt;
&lt;p&gt;Une timeline en temps réel très pratique était mise à disposition sur le site de React Advanced, avec les streams des deux tracks de conférence. C’était également appréciable de pouvoir mettre une conférence en pause ou revenir un peu en arrière pour mieux comprendre un point spécifique.
En revanche nous avons toutes deux trouvé qu’il était assez difficile de se concentrer, à cause des distractions inévitables de l’ordinateur mais aussi du &amp;quot;bruit&amp;quot; présent dans les streams eux-mêmes. Les vidéos contenaient beaucoup d’informations sur les conférences à venir, les tweets en rapport avec l’évènement, etc. qui venaient un peu polluer l’expérience.&lt;/p&gt;
&lt;p&gt;Dernier point regrettable, pas de &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://fr.wiktionary.org/wiki/v%C3%A9lotypie&quot;&gt;vélotypie&lt;/a&gt; sur les streams, ce qui aurait pourtant été un gros plus en termes d’accessibilité, ainsi que pour ceux dont l’anglais n’est pas la langue maternelle.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Une grosse partie des conférences était dédiée à React Native mais, étant toutes deux plutôt tournées développement Web, nous avons préféré assister aux conférences qui nous concernaient le plus.&lt;/p&gt;
&lt;p&gt;Des ateliers gratuits en remote sur des demi-journées étaient proposés aux participants sur des thèmes comme TypeScript ou React-Query.&lt;/p&gt;
&lt;p&gt;Dans l’ensemble ces deux jours de conférence ont été riches en enseignements, on espère pouvoir y assister à nouveau l’année prochaine et pourquoi pas vous y croiser !&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/nos-meetups-dautomne-en-suisse</id>
        <published>2018-11-23T13:49:00+01:00</published>
        <updated>2018-11-23T13:49:00+01:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/nos-meetups-dautomne-en-suisse"/>
        <title>Nos meetups d&#039;automne en Suisse 🏔️🇨🇭</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="conférence" />            <category term="symfony" />            <category term="react" />            <category term="traduction" />            <category term="animations" />            <category term="lottie" />        <summary><![CDATA[Depuis notre installation à Lausanne en février dernier, nous avons noué des liens avec plusieurs acteurs du Web en Suisse Romande. L&#039;occasion pour nous de partager nos expériences lors de meetups, comme…]]></summary>
        <content type="html">
            &lt;p&gt;Depuis notre installation à Lausanne en février dernier, nous avons noué des liens avec plusieurs acteurs du Web en Suisse Romande. L&#039;occasion pour nous de partager nos expériences lors de meetups, comme nous le faisons déjà en France depuis la création de JoliCode.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jolicode.com//blog/nos-tout-premiers-meetups-en-suisse&quot;&gt;Après Grégoire et Damien en juin dernier&lt;/a&gt;, c&#039;était au tour de &lt;a href=&quot;https://jolicode.com//equipe/vincent-desdoigts&quot;&gt;Vincent&lt;/a&gt; et Mathieu de partager leurs connaissances. Revenons ensemble sur ces 2 événements !&lt;/p&gt;
&lt;h2&gt;31 octobre - Les animations avec Lottie par Vincent&lt;/h2&gt;
&lt;blockquote class=&quot;instagram-media&quot; data-instgrm-captioned=&quot;true&quot; data-instgrm-permalink=&quot;https://www.instagram.com/p/BpmLhEonc-6/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot; data-instgrm-version=&quot;12&quot; style=&quot;background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:540px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);&quot;&gt;
&lt;p style=&quot;padding:16px;&quot;&gt;&lt;a style=&quot;background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener nofollow noopener noreferrer&quot; href=&quot;https://www.instagram.com/p/BpmLhEonc-6/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot;&gt;&lt;div style=&quot; display: flex; flex-direction: row; align-items: center;&quot;&gt; &lt;div style=&quot;background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 40px; margin-right: 14px; width: 40px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot;display: flex; flex-direction: column; flex-grow: 1; justify-content: center;&quot;&gt; &lt;div style=&quot; background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; margin-bottom: 6px; width: 100px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot; background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; width: 60px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;padding: 19% 0;&quot;&gt;&lt;/div&gt;&lt;div style=&quot;display:block; height:50px; margin:0 auto 12px; width:50px;&quot;&gt;&lt;svg height=&quot;50px&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 60 60&quot; width=&quot;50px&quot; xmlns=&quot;https://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;https://www.w3.org/1999/xlink&quot;&gt;&lt;g fill=&quot;none&quot; fill-rule=&quot;evenodd&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot;&gt;&lt;g fill=&quot;#000000&quot; transform=&quot;translate(-511.000000, -20.000000)&quot;&gt;&lt;g&gt;&lt;path d=&quot;M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div style=&quot;padding-top: 8px;&quot;&gt; &lt;div style=&quot; color:#3897f0; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:550; line-height:18px;&quot;&gt; Voir cette publication sur Instagram&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;padding: 12.5% 0;&quot;&gt;&lt;/div&gt;&lt;div style=&quot;display: flex; flex-direction: row; margin-bottom: 14px; align-items: center;&quot;&gt;&lt;div&gt; &lt;div style=&quot;background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(0px) translateY(7px);&quot;&gt;&lt;/div&gt; &lt;div style=&quot;background-color: #F4F4F4; height: 12.5px; transform: rotate(-45deg) translateX(3px) translateY(1px); width: 12.5px; flex-grow: 0; margin-right: 14px; margin-left: 2px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot;background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(9px) translateY(-18px);&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;margin-left: 8px;&quot;&gt; &lt;div style=&quot; background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 20px; width: 20px;&quot;&gt;&lt;/div&gt; &lt;div style=&quot; width: 0; height: 0; border-top: 2px solid transparent; border-left: 6px solid #f4f4f4; border-bottom: 2px solid transparent; transform: translateX(16px) translateY(-4px) rotate(30deg)&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;margin-left: auto;&quot;&gt; &lt;div style=&quot; width: 0px; border-top: 8px solid #F4F4F4; border-right: 8px solid transparent; transform: translateY(16px);&quot;&gt;&lt;/div&gt; &lt;div style=&quot; background-color: #F4F4F4; flex-grow: 0; height: 12px; width: 16px; transform: translateY(-4px);&quot;&gt;&lt;/div&gt; &lt;div style=&quot; width: 0; height: 0; border-top: 8px solid #F4F4F4; border-left: 8px solid transparent; transform: translateY(-4px) translateX(8px);&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin:8px 0 0 0; padding:0 4px;&quot;&gt;&lt;a rel=&quot;nofollow noopener nofollow noopener noreferrer&quot; style=&quot;color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;&quot; target=&quot;_blank&quot; href=&quot;https://www.instagram.com/p/BpmLhEonc-6/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot;&gt;Nous sommes aujourd’hui à l’@epflcampus pour animer le brown bag lunch d’Halloween 🎃. Merci à l’équipe de #laforge pour votre accueil ! Si vous souhaitez construire de super animations dans vos projets Web et mobiles, envoyez-nous un petit mot 👋🏼 #lottie #react #javascript #lausanne&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;&quot;&gt;Une publication partagée par &lt;a rel=&quot;nofollow noopener nofollow noopener noreferrer&quot; style=&quot;color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;&quot; target=&quot;_blank&quot; href=&quot;https://www.instagram.com/jolicode/?utm_source=ig_embed&amp;amp;utm_medium=loading&quot;&gt;JoliCode&lt;/a&gt; (@jolicode) le
&lt;time datetime=&quot;2018-10-31T11:55:11+00:00&quot; style=&quot; font-family:Arial,sans-serif; font-size:14px; line-height:17px;&quot;&gt;31 Oct. 2018 à 4 :55 PDT&lt;/time&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;//www.instagram.com/embed.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;Ce talk fut un retour d’expérience de Vincent (frontend &amp;amp; React-Native Developer) sur Lottie, un outil créé par Airbnb. Cette librairie open source permet d’inclure et d’exploiter des animations After Effects au format json. Elle offre un contrôle total sur celles-ci et la possibilité de les intégrer facilement dans une interface. Si vous souhaitez construire rapidement de super animations dans vos projets Web et mobiles, n’hésitez pas à consulter les slides de la conférence : vous y trouverez notamment des exemples et quelques mots sur LottieFiles.&lt;/p&gt;
&lt;p&gt;Une présentation pour deux éditions : celle du midi s’est déroulée au Brownbag lunch Halloween organisée à &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://epfl-innovationpark.ch/laforge&quot;&gt;La Forge, EPFL Innovation Park&lt;/a&gt;. Merci Marine Favre pour l’organisation ! Le soir, cela se passait du côté du meetup Frontend Romandie, organisé par &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/wengerk&quot;&gt;Kévin Wenger&lt;/a&gt; et hébergé par &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://antistatique.net/&quot;&gt;Antistatique&lt;/a&gt;. Merci à eux !&lt;/p&gt;
&lt;p&gt;🗒 &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://vdesdoigts.github.io/lottie-talk/#/&quot;&gt;Slides&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;21 novembre - Traduire efficacement une application Web par Mathieu&lt;/h2&gt;
&lt;p&gt;&lt;picture class=&quot;js-dialog-target&quot; data-original-url=&quot;/media/original/2018/meetupsautomne/meetup-gotham.JPG&quot; data-original-width=&quot;4032&quot; data-original-height=&quot;3024&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2018/meetupsautomne/meetup-gotham.a6d893a6.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2018/meetupsautomne/meetup-gotham.JPG&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 996px; ; aspect-ratio: calc(4032 / 3024)&quot; src=&quot;https://jolicode.com//media/cache/content/2018/meetupsautomne/meetup-gotham.JPG&quot; alt=&quot;meetup php user group&quot; title=&quot;Meetup PHP User Group&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;C’est dans le grand espace Gotham Gare que se déroulait le Meetup. Mathieu y présentait son retour d&#039;expérience sur la traduction d&#039;une application PHP.&lt;/p&gt;
&lt;p&gt;La traduction est une étape cruciale de la réalisation d&#039;un projet Web. Elle l&#039;est d&#039;autant plus en Suisse, où près de 90% des créations Web nécessitent d&#039;être localisées dans au moins deux langues. Cependant, sa mise en place est souvent douloureuse et reste compliquée tout au long de la vie de l&#039;application. Un nouveau type d&#039;intervenant entre en jeu, en plus des développeurs, chefs de projets, designers, voici maintenant les traducteurs.&lt;/p&gt;
&lt;p&gt;Fort de son expérience pendant le projet &lt;a href=&quot;https://jolicode.com//nos-clients/ouibus&quot;&gt;Ouibus&lt;/a&gt;, Mathieu nous a fait part des problèmes rencontrés couramment lors de la traduction d&#039;un projet web, mais surtout des solutions que l&#039;on peut mettre en place pour contrer ces problèmes. Parmi elles, nous trouvons notamment l&#039;importance d&#039;outiller correctement son projet et surtout de trouver le bon outil pour le bon intervenant ; un traducteur n&#039;a pas envie de mettre les mains dans un fichier XML contenant les clés de traduction, il préférera avoir un outil pourvu d&#039;une interface graphique, facile à appréhender.&lt;/p&gt;
&lt;p&gt;Après la présentation, un quiz était proposé au public avec 8 questions portant sur les points les plus importants abordés précédemment. Le gagnant est reparti avec &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://boutique.letrainde13h37.fr/products/la-dette-technique-bastien-jaillot&quot;&gt;le livre de Bastien sur la Dette Technique&lt;/a&gt; !&lt;/p&gt;
&lt;p&gt;🗒 &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://welcomattic.github.io/traduire-efficacement-une-app-symfony/meetup-php-lausanne/index.html&quot;&gt;Slides&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;En 2019 : fusion des meetups PHP User Groupe Romand et Frontend Romandie&lt;/h2&gt;
&lt;p&gt;Grande nouveauté ! &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/wengerk&quot;&gt;Kévin Wenger&lt;/a&gt; a annoncé la future fusion de ces deux entités en une seule : les &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://webmardi.ch/&quot;&gt;Webmardi&lt;/a&gt;. L’objectif est d’unir les forces de ces deux communautés pour proposer des événements toujours de plus grande qualité, qui favorisent l’échange d’expertises et le partage. Une nouvelle identité graphique, un cycle de 11 rendez-vous et un nouveau format (open mic, stream live, kahoot! game, etc.) sont attendus.&lt;/p&gt;
&lt;p&gt;Merci encore aux organisateurs pour ces événements ! On ne peut que vous inviter à rejoindre &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.meetup.com/fr-FR/webmardi/events/256591479/&quot;&gt;le traditionnel Webmardi de fin d’année&lt;/a&gt; qui aura lieu le 4 décembre, et qui se terminera par une fondue à l&#039;Évêché  #legrascestlavie 🧀 . 2019 est bientôt là, nous avons hâte de discuter avec vous de PHP, Symfony ainsi que de JavaScript, React / React Native, Docker, Elasticsearch, RabbitMQ ou bien encore Go, nos thèmes de prédilection ❤️.&lt;/p&gt;
&lt;p&gt;N’hésitez pas à venir nous rencontrer dans &lt;a href=&quot;https://jolicode.com//contact#suisse&quot;&gt;nos bureaux Lausannois&lt;/a&gt;, nous nous ferons un plaisir de partager un café avec vous !&lt;/p&gt;
&lt;p&gt;Bye bye ! 👋&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/retours-de-react-europe-2018</id>
        <published>2018-06-11T13:42:00+02:00</published>
        <updated>2018-06-11T13:42:00+02:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/retours-de-react-europe-2018"/>
        <title>Retours de React Europe 2018</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="react" />            <category term="reactnative" />            <category term="reacteurope" />        <summary><![CDATA[Il y a 5 ans, Facebook ajouta sa contribution à l’écosystème JavaScript en publiant la première version de React. Depuis cette dernière s’est hissée au rang des incontournables, dépassant son simple rôle…]]></summary>
        <content type="html">
            &lt;p&gt;Il y a 5 ans, Facebook ajouta sa contribution à l’écosystème JavaScript en publiant la première version de React. Depuis cette dernière s’est hissée au rang des incontournables, dépassant son simple rôle de librairie.&lt;/p&gt;
&lt;h2&gt;React ❤️&lt;/h2&gt;
&lt;p&gt;React est aujourd’hui un vrai écosystème à part entière : nouveaux paradigmes, révolution de l’expérience de développement. Un écosystème qui s’est étendu jusqu’au développement mobile avec React Native. Il fédère une communauté éclectique et passionnée : développeurs back / front, designers, développeurs mobiles, apportant chaque jour de nouvelles contributions.&lt;/p&gt;
&lt;p&gt;Nous étions présents à la 4ème édition de React Europe à Paris pour rencontrer, écouter, discuter avec cette belle communauté dont nous faisons partie depuis maintenant deux ans.&lt;/p&gt;
&lt;h2&gt;Les conférences&lt;/h2&gt;
&lt;p&gt;Bonne nouvelle, l’ensemble des conférences a été filmé et diffusé en direct 🔴, vous pouvez retrouver l’intégralité des talks sur les playlists suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/playlist?list=PLCC436JpVnK3xH_ArpIjdkYDGwWNkVa73&quot;&gt;Journée 1&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/playlist?list=PLCC436JpVnK1X7atG6EIz467Evs4TMX_5&quot;&gt;Journée 2&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/playlist?list=PLCC436JpVnK1blGoSX8rH55pdF05TfWJn&quot;&gt;Lighting talks&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aucune excuse donc pour ne pas être au courant des dernières nouveautés, pour les plus pressés, voici un résumé de quelques talks qui nous ont plu.&lt;/p&gt;
&lt;h3&gt;Keynote : New hotness in React&lt;/h3&gt;
&lt;p&gt;🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/ken_wheeler&quot;&gt;https://twitter.com/ken_wheeler&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=QFk6YwMz8nc&quot;&gt;https://www.youtube.com/watch?v=QFk6YwMz8nc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;La conférence s’est ouverte sur la keynote énergisante de Ken Wheeler (à la tête de FormidableLabs, qui a entre autre développé Spectacle) passant en revue les dernières nouveautés de React.&lt;/p&gt;
&lt;p&gt;Au menu, une piqûre de rappel sur la nouvelle Context API, nouveaux événements de composants (dépréciation de &lt;code&gt;componentWillReceiveProps&lt;/code&gt; en faveur de &lt;code&gt;getDerivedStateFromProps&lt;/code&gt;), mise en pratique de la fameuse API Suspense. Cette dernière, présentée par Dan Abramov &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=v6iR3Zk4oDY&quot;&gt;lors de la JSConf Iceland&lt;/a&gt; a été mergée dans la &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/react/pull/12279&quot;&gt;branche master&lt;/a&gt;, hold your horses ! Pour rappel, Suspense permet de mettre en pause le rendu de composant lors d’appels asynchrones et gérer plus finement les états de chargement et mise en cache.&lt;/p&gt;
&lt;h3&gt;The Case for Whimsy&lt;/h3&gt;
&lt;p&gt;🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/joshwcomeau&quot;&gt;https://twitter.com/joshwcomeau&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=Z2d9rw9RwyE&quot;&gt;https://www.youtube.com/watch?v=Z2d9rw9RwyE&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Joshua est un nostalgique de l’internet des années 90 où les pages arboraient leurs plus beaux wordart et GIFs. Il souhaite revenir à un internet fun mais qui a du sens sans délaisser l’accessibilité.&lt;/p&gt;
&lt;p&gt;Son talk montre l’exploration effectuée pour trouver des animations performantes et satisfaisante pour l’utilisateur. Le premier cas est une animation canvas pour créer des confettis lors du succès d’un quizz Khan Academy dont il est l&#039;un des développeurs. Il détaille particulièrement l’implémentation utilisant les lifecycles des composants ainsi que la synchronisation du rendu de React avec les « animations frames ».&lt;/p&gt;
&lt;p&gt;Le deuxième exemple consiste en une animation lancée par l’utilisateur (action driven) du DOM pour un client mail via la manipulation du DOM avec React et du CSS. L’API qui en résulte est claire et abstraite, ce qui permet à ces animations d’être appliquées facilement à n’importe quels composants.&lt;/p&gt;
&lt;p&gt;Josh finalise son talk sur les améliorations à venir quant aux animations CSS avec Firefox Web Render. Celui-ci utilise l’accélération matérielle pour toutes les propriétés ! Enfin, il recentre notre attention sur l’accessibilité et l’utilisation d’animations avec parcimonie. Celles-ci doivent ajouter une réelle plus-value.&lt;/p&gt;
&lt;h3&gt;Declarative future of gestures and animations in React Native&lt;/h3&gt;
&lt;p&gt;🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/kzzzf&quot;&gt;https://twitter.com/joshwcomeau&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://youtu.be/kdq4z2708VM&quot;&gt;https://youtu.be/kdq4z2708VM&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;L&#039;animation avec React Native est un sujet fréquent, de nombreuses publications pour reproduire des interfaces connues comme l’application Tinder ou encore Uber existent.&lt;/p&gt;
&lt;p&gt;Krzysztof Magiera (co-créateur de React Native) nous explique la manière dont sont implémentées les animations. Souvent synonyme de mauvaises performances car définies dans notre code JS, certaines ne peuvent pas être liées directement à des propriétés natives, ce qui force des aller/retour sur le bridge React Native. Le moniteur de performance nous permet de suivre les frames par seconde de chaque thread et ainsi voir l’impact d’une animation sur les performances.&lt;/p&gt;
&lt;p&gt;Ceci devient encore plus complexe quand l’on veut synchroniser des gestes avec un effet d’animation. Par exemple au scroll d’une ListView. Pour pallier ces différents problèmes, Krzysztof a créé le module &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/kmagiera/react-native-gesture-handler&quot;&gt;react-native-gesture-handler&lt;/a&gt; qui est maintenant disponible automatiquement dans Expo. En plus de proposer une API simple autour du driver natif d’animation, plusieurs composants sont implémentés pour créer un comportement « Swipeable » ou une navigation de type « drawer ».&lt;/p&gt;
&lt;h3&gt;A Journey through React Apollo&lt;/h3&gt;
&lt;p&gt;🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/peggyrayzis&quot;&gt;https://twitter.com/peggyrayzis&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=fCXYA3lZTbo&quot;&gt;https://www.youtube.com/watch?v=fCXYA3lZTbo&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apollo manages updating your data just like React manages updating your UI&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GraphQL fut à l’honneur pendant ces deux journées de conférences, notamment par l’intermédiaire de Peggy Rayzis, core team d’Apollo. Celle-ci nous a présenté les dernières fonctionnalités en rappelant les promesses du produit :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Plus besoin de Redux pour vos données serveur ;&lt;/li&gt;
&lt;li&gt;Plus besoin de normalisation via Normalizr ;&lt;/li&gt;
&lt;li&gt;Plus besoin de typage / PropType.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Elle a conclu son talk en présentant le futur d’Apollo avec sa version 3. Les nouveautés résident principalement sur l’intégration de la nouvelle API Suspense.&lt;/p&gt;
&lt;h3&gt;Replicated Redux&lt;/h3&gt;
&lt;p&gt;🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/jimpurbrick&quot;&gt;https://twitter.com/jimpurbrick&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://youtu.be/Fr3vp0C22H0&quot;&gt;https://youtu.be/Fr3vp0C22H0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jim Purbrick nous a livré un talk inspirant, sortant des usages traditionnels de React : l’intégration de Redux dans une architecture multi-clients. En effet, Redux, de par son architecture, est idéal pour répliquer les actions au travers de différents clients en les dispatchant. Jim, lead-developpeur de ReactVR nous a montré comment répondre aux problématiques de synchronisation, anticipation, concepts que l’on retrouve dans le &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://en.wikipedia.org/wiki/Netcode&quot;&gt;Netcode&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Beyond React&lt;/h3&gt;
&lt;p&gt;🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/dvnabbott&quot;&gt;https://twitter.com/dvnabbott&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://youtu.be/HVwLOcllTfI&quot;&gt;https://youtu.be/HVwLOcllTfI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cette conférence nous fait réfléchir à l’approche composant et à notre manière de travailler avec ceux-ci. En effet la plupart du temps une équipe dédiée au design va travailler avec des outils spécifiques comme Sketch ou Illustrator puis, d’autres personnes vont créer des composants React. Hélas il n’y a pas de piliers communs entre ces deux équipes. C’est la problématique que cherche à résoudre &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/airbnb/Lona&quot;&gt;Lona&lt;/a&gt;, l’outil présenté dans ce talk. Doté d’un UI builder, d’un format standard et d’un compilateur vers du code React/JSX, il devient possible de compiler des UIs en composants React. Nous avons hâte d’essayer sur un petit projet pour renforcer la liaison entre nos équipes.&lt;/p&gt;
&lt;h3&gt;Bridging React Native Back to its Roots&lt;/h3&gt;
&lt;p&gt;🥇&lt;strong&gt;Prix de la meilleur démo 2018&lt;/strong&gt;
🐦&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/vincentriemer&quot;&gt;https://twitter.com/dvnabbott&lt;/a&gt;
🍿&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://youtu.be/aOWIJ4Mgb2k&quot;&gt;https://youtu.be/aOWIJ4Mgb2k&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;La conférence la plus impressionnante de cette édition, était celle de Vincent. Ce dernier est revenu sur les différences d’implémentation entre React et React Native (navigation, layout…) avant de proposer son postulat : pourquoi ne pourrait-on pas fusionner ces deux implémentations ? Une application React Native serait compatible web « out of the box ».&lt;/p&gt;
&lt;p&gt;C&#039;est déjà la promesse de &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/necolas/react-native-web&quot;&gt;react-native-web&lt;/a&gt;, mais pour Vincent, celle-ci a ses limites :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implémentation du layout (via flex) différente ;&lt;/li&gt;
&lt;li&gt;react-native-web est &amp;quot;web first&amp;quot; ;&lt;/li&gt;
&lt;li&gt;Différents systèmes de build ;&lt;/li&gt;
&lt;li&gt;Une grosse partie de l&#039;API de RN manquante.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour pallier ces limites, Vincent a développé un portage de React Native pour le web. &lt;em&gt;Introducing&lt;/em&gt; &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/vincentriemer/react-native-dom&quot;&gt;react-native-dom&lt;/a&gt; ✨. La promesse est un support à 100% de l&#039;API avec le même système de build (metro). La librairie n&#039;est pas encore exploitable en production mais tient de très belles promesses. Vous pouvez suivre l&#039;évolution du support de l&#039;API de React Native ici : &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://rntester.now.sh&quot;&gt;https://rntester.now.sh/&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;L&#039;organisation&lt;/h2&gt;
&lt;p&gt;Comme son nom l’indique, React Europe est le plus gros événement européen React qui par chance a lieu depuis son lancement à Paris. C’est une très belle occasion de rencontrer la communauté et faire le plein de motivation.&lt;/p&gt;
&lt;p&gt;Les conférences de 30 minutes suivent un bon rythme (environ 4 le matin et 6 l’après-midi), le tout ponctué de quelques pauses cerveau/café, rendent l’ensemble dynamique et sans temps morts. Comme d’habitude les petits-déjeuner, déjeuner (et même diner pour le jeudi soir) sont excellents, attention tout de même aux verres de vin / bières en trop le midi, effet sieste garanti 🍷.&lt;/p&gt;
&lt;h2&gt;Et ensuite ?&lt;/h2&gt;
&lt;p&gt;Les différentes conférences de cette édition 2018, remontent quelques tendances :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La volonté de convergence entre React et React Native  ;&lt;/li&gt;
&lt;li&gt;Améliorer l&#039;expérience développeur ;&lt;/li&gt;
&lt;li&gt;GraphQL comme nouveau standard pour les APIs ;&lt;/li&gt;
&lt;li&gt;L&#039;insoutenable attente de l&#039;API Suspense. 🙌&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;De nouveaux enjeux et défis donc pour la communauté React qui n&#039;a cessé d&#039;en relever ! À l&#039;année prochaine ! 👋&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/handling-dependencies-conflict-and-locking-in-react-native</id>
        <published>2018-01-10T09:42:00+01:00</published>
        <updated>2018-01-10T09:42:00+01:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/handling-dependencies-conflict-and-locking-in-react-native"/>
        <title>Handling dependencies conflict and locking in React Native</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="mobile" />            <category term="react" />            <category term="react-native" />        <summary><![CDATA[UPDATE 08/2018 : This article is deprecated, you can now handle this very easily with native dependency locking with Gradle &amp;gt;= 4.8.

Developing React Native apps is fast and enjoyable because we rarely…]]></summary>
        <content type="html">
            &lt;p&gt;&lt;em&gt;UPDATE 08/2018 : This article is deprecated, you can now handle this very easily with &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://docs.gradle.org/4.8.1/userguide/dependency_locking.html&quot;&gt;native dependency locking with Gradle &amp;gt;= 4.8&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Developing React Native apps is fast and enjoyable because we rarely have to deal with the native part of the application thanks to all the native modules available. Sadly, sometimes we encounter issues very close to the iOS or Android native development side. Recently, we came across a module conflict and locking issue on Android.&lt;/p&gt;
&lt;h2&gt;The problem&lt;/h2&gt;
&lt;p&gt;The app we were working on is dependent on many native modules and specifically these two:&lt;/p&gt;
&lt;p&gt;🗂 &lt;code&gt;/app/android/app/build.gradle&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-9&quot;&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;    compile&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; project&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;&#039;:react-native-firebase-analytics&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;    compile&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; project&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;&#039;:react-native-onesignal&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which gives us, after trying to build… 💥&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;:app:transformClassesWithJarMergingForDebug&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; FAILED&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;FAILURE:&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; Build&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; failed&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; with&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; an&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; exception.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; What went wrong:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;Execution&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; failed&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; task&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;:app:transformClassesWithJarMergingForDebug&#039;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/google/android/gms/common/api/internal/zzcc.class&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After some googling and browsing some stackoverflow issues, it seems that this is linked to a conflicting library, sadly not much more information is available about where to look.&lt;/p&gt;
&lt;p&gt;Gradle has a nice command to display the dependency tree that might help us.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; ./gradlew&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; app:dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;+---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; project&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; :react-native-firebase-analytics&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.facebook.react:react-native:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 0.48.4&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-core:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 11.4.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    \---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-analytics:11.4.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;         +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-common:11.4.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;         |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.android.gms:play-services-basement:11.4.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-9&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    \---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-analytics:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 11.4.0&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;+---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; project&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; :react-native-onesignal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.facebook.react:react-native:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 0.48.4&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.onesignal:OneSignal:3.+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 3.6.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.android.gms:play-services-gcm:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 11.0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.android.gms:play-services-base:11.0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.android.gms:play-services-basement:11.0.2&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that both &lt;code&gt;react-native-firebase-analytics&lt;/code&gt; and &lt;code&gt;react-native-onesignal&lt;/code&gt; depends on &lt;code&gt;com.google.android.gms:play-services-basement&lt;/code&gt; but with different versions.&lt;/p&gt;
&lt;h2&gt;The solution&lt;/h2&gt;
&lt;p&gt;Via Gradle, we can exclude the conflicting module &lt;code&gt;com.google.android.gm&lt;/code&gt; from both our dependencies like so and then ask for a specific version. This also prevents including too many libs from Google play services in our APK (less bundled code, yeah!).&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;    compile&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;:react-native-firebase-analytics&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        exclude group&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;com.google.android.gms&#039;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;    compile&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;:react-native-onesignal&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        exclude group&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;com.google.android.gms&#039;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    compile &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;com.google.android.gms:play-services-gcm:11.4.0&#039;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    compile &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;com.google.android.gms:play-services-basement:11.4.0&#039;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Locking Android dependencies&lt;/h3&gt;
&lt;p&gt;After solving the conflict and trying to compile again a few weeks later, we got the same issue back without any native code modification of our app! 💥&lt;/p&gt;
&lt;p&gt;This time the Gradle command showed us this:&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;+---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; project&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; :react-native-onesignal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.facebook.react:react-native:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 0.48.4&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    \---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.onesignal:OneSignal:3.+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 3.6.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;+---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; project&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; :react-native-firebase-analytics&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.facebook.react:react-native:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 0.48.4&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-core:+&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 11.6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    \---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-analytics:11.6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;         +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.firebase:firebase-common:11.6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;    |&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;         |&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;    +---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.android.gms:play-services-basement:11.6.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;+---&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; com.google.android.gms:play-services-basement:11.4.0&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; 11.6.0&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (*)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;react-native-onesignal&lt;/code&gt; still got the dependency excluded but &lt;code&gt;com.google.firebase:firebase-core&lt;/code&gt; now requires the &lt;code&gt;11.6.0&lt;/code&gt; version. Since the dependency is not explicitly locked by the module, gradle resolves it with the latest version available.&lt;/p&gt;
&lt;p&gt;Changing these two lines to require the latest version fixed the issue, but just until the next release of the firebase module...&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;compile &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;com.google.android.gms:play-services-gcm:11.4.0&#039;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    compile &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;com.google.android.gms:play-services-basement:11.4.0&#039;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a JavaScript project, we usually go with yarn or npm to manage dependencies. Thankfully, since yarn came out, we got a nice &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://yarnpkg.com/lang/en/docs/yarn-lock/&quot;&gt;yarn.lock&lt;/a&gt; file to lock our dependencies and the npm equivalent &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://docs.npmjs.com/files/package-locks&quot;&gt;package-lock.json&lt;/a&gt;. Gradle has no built-in system for this but Netflix solved it with a nice plugin.&lt;/p&gt;
&lt;p&gt;To use this plugin, add this at the top of your &lt;code&gt;android/app/build.gradle&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;apply plugin&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;nebula.dependency-lock&#039;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this to &lt;code&gt;android/build.gradle&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    classpath &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;com.netflix.nebula:gradle-dependency-lock-plugin:4.+&#039;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then the command &lt;code&gt;cd android &amp;amp;&amp;amp; ./gradlew generateLock saveLock&lt;/code&gt; will generate a nice &lt;code&gt;android/app/dependencies.lock&lt;/code&gt; that you can add to git to be sure to always have the same dependencies on every installation.&lt;/p&gt;
&lt;p&gt;Native knowledges are always nice to have while working on a React Native project, those tips will improve the stability of your project with strict reproducible builds.
We are glad to only had this problem on Android since &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://blog.sigmapoint.pl/avoiding-dependency-collisions-in-ios-static-library-managed-by-cocoapods/&quot;&gt;it seems way more complicated on iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jolicode.com//&quot;&gt;https://jkutner.github.io/2017/03/29/locking-gradle-dependencies.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jolicode.com//&quot;&gt;https://nebula-plugins.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/marier-react-et-symfony</id>
        <published>2017-08-02T14:30:00+02:00</published>
        <updated>2017-08-02T14:30:00+02:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/marier-react-et-symfony"/>
        <title>Marier React et Symfony</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="conférence" />            <category term="symfony" />            <category term="react" />            <category term="phptour" />            <category term="limeniusreactbundle" />        <summary><![CDATA[Cet article fait suite à notre conférence &amp;quot;Comment marier Symfony et React ?&amp;quot; présentée au PHP Tour 2017.
On ne présente plus React, framework JavaScript bien connu et à la pointe de la mode…]]></summary>
        <content type="html">
            &lt;p&gt;Cet article fait suite à notre conférence &amp;quot;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://jolicode.github.io/react-et-symfony-conf/&quot;&gt;Comment marier Symfony et React ?&lt;/a&gt;&amp;quot; présentée au PHP Tour 2017.&lt;/p&gt;
&lt;p&gt;On ne présente plus &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;, framework JavaScript bien connu et à la pointe de la mode depuis 2 ans déjà. Les tutoriels / articles pour créer votre projet en React ne manquent pas sur les Internets : on crée une API, puis un front full React pour la consommer. Ce n’est donc pas cette approche que nous vous proposons de discuter ici mais plutôt comment utiliser React dans un projet Symfony existant, sans nécessairement découpler les deux.&lt;/p&gt;
&lt;p&gt;Pour ce faire, nous retenons deux solutions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;utiliser React directement ;&lt;/li&gt;
&lt;li&gt;utiliser &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/Limenius/ReactBundle&quot;&gt;LimeniusReactBundle&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les deux méthodes sont similaires sur beaucoup d’aspects, la qualité principale de LimeniusReactBundle sera de vous permettre de mettre facilement en place le rendu serveur de vos composants, ainsi que d’avoir accès à des extensions Twig pour faciliter l’intégration de React dans vos templates.&lt;/p&gt;
&lt;p&gt;Mais commençons par le commencement. React, on ne le présente plus certes, mais chacun n’est pas familier pour autant avec ses concepts de base. Ceux-ci peuvent se résumer (grosso modo) en trois points :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;des composants écrits en JSX ;&lt;/li&gt;
&lt;li&gt;qui ont des props et un state ;&lt;/li&gt;
&lt;li&gt;un algorithme de réconciliation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si vous connaissez déjà React, aller directement à la partie &lt;a href=&quot;#react-symfony&quot;&gt;React et Symfony&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour la suite de cet article, nous allons choisir un exemple simple : la réalisation d’une todo list. Les spécifications sont les suivantes :
afficher une liste de choses à faire ;
pouvoir marquer un élément de la liste comme &amp;quot;fait&amp;quot; afin qu’il disparaisse de la liste ;
le tout dans une page &lt;strong&gt;déjà écrite avec Twig&lt;/strong&gt; ;
avec des données (éléments de la liste) provenant d’un contrôleur Symfony.&lt;/p&gt;
&lt;h2&gt;React en bref&lt;/h2&gt;
&lt;h3&gt;Grands principes : réconciliation et DOM virtuel&lt;/h3&gt;
&lt;p&gt;Pour agir sur l’affichage dans le navigateur, React utilise un système de &lt;em&gt;DOM virtuel&lt;/em&gt;, combiné à un algorithme de différenciation : la réconciliation. Concrètement, chaque élément du DOM ainsi que son état dans le DOM physique du navigateur est répercuté dans un DOM virtuel construit par React. Voici un schéma explicatif :
&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/react-symfony/react-dom.755d0093.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2017/react-symfony/react-dom.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 807px; ; aspect-ratio: calc(807 / 511)&quot; src=&quot;https://jolicode.com//media/cache/content/2017/react-symfony/react-dom.png&quot; alt=&quot;React DOM&quot; title=&quot;React DOM&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Quand une modification survient, du côté du navigateur (l’utilisateur clique sur un bouton (1)) cela déclenche un événement (2) que React écoute et utilise son algorithme pour calculer la différence entre le DOM physique et le DOM virtuel (3). Il génère ainsi un certain nombre d’opérations à effectuer pour &lt;em&gt;réconcilier&lt;/em&gt; ces deux états, les synchroniser, puis applique (4) ces modifications grâce à l’API DOM du navigateur.&lt;/p&gt;
&lt;p&gt;Une modification peut survenir directement du côté de React (un appel à une API renvoie une liste d’éléments qui sera affichée), dans ce cas on est directement dans l’étape (3).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;À savoir&lt;/em&gt; : Alors que l’algorithme de réconciliation est partie intégrante de la librairie React, le DOM virtuel ne provient pas à proprement parler de React mais de ReactDOM. Dans le cas de React Native, on utilise d’autres méthodes pour appliquer les modifications générées par l’algo, puisqu’une application mobile ne fonctionne pas grâce à un DOM. Le principe reste cependant le même.&lt;/p&gt;
&lt;h3&gt;Les composants&lt;/h3&gt;
&lt;p&gt;Une application React peut être représentée par un ensemble de &lt;strong&gt;composants&lt;/strong&gt; imbriqués les uns dans les autres. L’intérêt majeur de cette architecture est qu’elle permet d’avoir des &amp;quot;morceaux de code&amp;quot; &lt;strong&gt;réutilisables&lt;/strong&gt;. On va donc écrire nos composants en se basant sur un postulat simple : une responsabilité (même mineure) = un composant.&lt;/p&gt;
&lt;p&gt;Reprenons notre exemple, on veut afficher une liste de choses à faire, avec un bouton permettant de marquer un élément comme fait. On aura donc trois composants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le composant parent qui représente la liste de choses à faire (&lt;em&gt;TodoList&lt;/em&gt;) ;&lt;/li&gt;
&lt;li&gt;le composant qui représente une chose à faire (&lt;em&gt;Todo&lt;/em&gt;) ;&lt;/li&gt;
&lt;li&gt;le composant qui représente le bouton d’action (&lt;em&gt;TodoButton&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chacun de ces composants implémente la méthode render() qui définit le rendu de ce composant. Ce rendu peut-être constitué de code HTML (ou plutôt pseudo-HTML, grâce à JSX) et/ou d’autres composants imbriqués.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;TodoList&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; extends&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-7&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  render&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; className&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;well&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        {&lt;/span&gt;&lt;span class=&quot;syntax-10&quot;&gt;/* code du rendu */&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Le rendu d’un composant à un instant t dépend de deux sources de données : les &lt;em&gt;props&lt;/em&gt; et le &lt;em&gt;state&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Les props et le state&lt;/h3&gt;
&lt;p&gt;On peut comparer un composant à une fonction, qui reçoit des paramètres (les props) et manipule également des variables locales (le state).&lt;/p&gt;
&lt;p&gt;Les props sont passées à un composant soit par le composant appelant (&lt;code&gt;&amp;lt;Todo item=&amp;quot;Acheter du lait&amp;quot; done={false} /&amp;gt;&lt;/code&gt;), soit par des décorateurs (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/yahoo/react-intl/wiki/API#injectintl&quot;&gt;injectIntl&lt;/a&gt; par exemple, proposé par react-intl et qui permet d’injecter la prop &lt;code&gt;intl&lt;/code&gt;, de manière à gérer des traductions, dans un composant). On parle ici de flux de données &lt;em&gt;unidirectionnel&lt;/em&gt; : les props sont toujours transmises du parent vers l’enfant et jamais en sens inverse.&lt;/p&gt;
&lt;p&gt;Le state quant-à-lui représente l’état d’un composant, il est défini à l’intérieur du composant lui-même, qui en a alors la responsabilité.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;Todo&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; extends&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-7&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  constructor&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-11&quot;&gt;	super&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-11&quot;&gt;  	this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.state &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      visible: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  	};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  markAsDone&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-11&quot;&gt;    this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	  visible: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  render&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    if&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.state.visible) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;	  return&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; null&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;	return&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	  &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	    &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.props.item&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;		&amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; onClick&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.markAsDone.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;			Fait&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;		&amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	  &amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cette introduction à React est volontairement concise, et nous vous invitons pour aller plus loin à vous référer à la &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/docs/hello-world.html&quot;&gt;documentation existante&lt;/a&gt;, très bien fournie. Une liste de références intéressantes est à votre disposition à la fin de l’article.&lt;/p&gt;
&lt;h2 id=&quot;react-symfony&quot;&gt;React et Symfony&lt;/h2&gt;
&lt;p&gt;De plus en plus de projets utilisent conjointement React et Symfony. Il existe deux manières principales de marier ces deux technologies, que nous allons étudier ensemble.&lt;/p&gt;
&lt;h3&gt;React se nourrit de votre API&lt;/h3&gt;
&lt;p&gt;Si vous disposez d’une API existante, c’est certainement la solution la plus adaptée, peu importe d’ailleurs que votre API utilise Symfony ou non.&lt;/p&gt;
&lt;p&gt;Comme dit plus haut, nous ne détaillerons pas ici la mise en place de cette architecture. Vous trouverez plusieurs liens vers des articles détaillant cette architecture et sa mise en place à la fin de l’article, si c’est cette solution qui vous intéresse.&lt;/p&gt;
&lt;p&gt;En revanche, nous avons jugé intéressant de mettre l’accent sur quelques détails d’implémentations, basés sur notre expérience personnelle.&lt;/p&gt;
&lt;h4&gt;Logique métier&lt;/h4&gt;
&lt;p&gt;Dans des projets avec une logique métier forte, séparez au maximum les responsabilités pour éviter d’avoir à dupliquer la logique métier.&lt;/p&gt;
&lt;p&gt;Dans le cas d’un site d’e-commerce avec workflow de commandes complexes par exemple, vous pouvez pour chaque commande, passer dans votre API son état et les transitions possibles. Ainsi, côté React vous aurez juste à créer des boutons permettant d’appliquer ces transitions, sans vous soucier de leur signification, et donc sans dupliquer la logique métier.&lt;/p&gt;
&lt;p&gt;De la même manière, évitez de redéfinir des énumérations ou des listes de constantes, il est très rapide de mettre en place une méthode d’API qui retourne la liste de chacune des constantes, d’appeler cette méthode à chaque premier chargement de votre site React, puis de stocker ces valeurs dans un store global grâce à redux par exemple. Vous y aurez ainsi accès n’importe où dans vos composants et cela vous permettra d’avoir un code plus facilement maintenable.&lt;/p&gt;
&lt;p&gt;Ce principe ne vaut pas pour tous les cas évidemment, la validation d’un formulaire, même si elle est complexe, devra quand même être implémentée des deux côtés (du moins si vous souhaitez des formulaires agréables à utiliser).&lt;/p&gt;
&lt;h4&gt;Internationalisation&lt;/h4&gt;
&lt;p&gt;Dans le cas d’un site multi-langues, il existe deux stratégies principales :&lt;/p&gt;
&lt;h5&gt;Tout traduire côté API&lt;/h5&gt;
&lt;p&gt;Vos messages quels qu’ils soient sont renvoyés traduits dans toutes les langues supportées et prêts à être affichés. Dans les faits cela peut poser problème puisqu’il devient impossible de changer le wording côté React. On peut également mettre en place un mécanisme pour préciser à l’API la langue souhaitée (avec un header Accept-Language dans vos requêtes par exemple), afin de récupérer seulement les traductions dans la ou les langues souhaitées.&lt;/p&gt;
&lt;h5&gt;Passer des clés de traductions via l’API, et traduire côté React&lt;/h5&gt;
&lt;p&gt;Simple à mettre en place côté API, il faudra cependant faire attention aux exceptions et aux erreurs de validations qui peuvent avoir des messages par défaut. Côté React, il faudra également implémenter un mécanisme pour réaliser ces traductions (par exemple en utilisant react-intl), et déporter tout le catalogue de message côté React, ce qui peut s’avérer plus gourmand en ressources. Il est possible (de la même manière que pour les constantes), de conserver le catalogue de messages côté API, et de le récupérer via un appel HTTP, mais on retrouvera alors les mêmes problèmes que pour la solution précédente.&lt;/p&gt;
&lt;p&gt;Aucune de ces solutions n’est meilleure que l’autre, il faudra juste choisir la plus adaptée à votre cas et surtout vous y tenir sur tous les aspects du projet (messages d’erreur, erreurs de validation, etc...).&lt;/p&gt;
&lt;h4&gt;Librairies existantes&lt;/h4&gt;
&lt;p&gt;Si vous souhaitez réaliser un back-office avec cette architecture (un cas très fréquent et bien documenté), il existe de nombreuses technologies &amp;quot;clé en main&amp;quot; qui permettent de réaliser un back-office en React avec une API Symfony.&lt;/p&gt;
&lt;p&gt;Parmi celles-ci on peut citer &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/marmelab/admin-on-rest&quot;&gt;admin-on-rest&lt;/a&gt;, qui permet de réaliser très rapidement une interface d’administration basée sur une API existante et quel que soit le format utilisé par cette API. Il vous faudra simplement créer un &amp;quot;client&amp;quot;, qui prend en paramètre le type d’action que vous souhaitez effectuer (&lt;code&gt;GET_ONE&lt;/code&gt;, &lt;code&gt;GET_LIST&lt;/code&gt;, &lt;code&gt;CREATE&lt;/code&gt;...), la ressource (article, commentaire…), et un ensemble de paramètres (une représentation json d’un objet à créer par exemple) et qui exécute la requête adéquate et retourne une promesse.
&lt;code&gt;restClient(GET_ONE, &#039;posts&#039;, { id: 123 })&lt;/code&gt;
Il est également possible très facilement de personnaliser votre back-office.&lt;/p&gt;
&lt;p&gt;Si vous utilisez api-platform pour votre API, vous pouvez également mettre en place un back-office en utilisant &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/api-platform/admin&quot;&gt;api-platform-admin&lt;/a&gt;. Cette librairie, basée sur &lt;code&gt;admin-on-rest&lt;/code&gt;, permet de créer très rapidement le back-office correspondant à votre API (en parsant la documentation de l’API pour déterminer seul les routes existantes). La librairie a l’avantage d’être extrêmement rapide à mettre en place et on a la possibilité de le &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/api-platform/admin#customize-the-admin&quot;&gt;personnaliser complètement&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;React embarqué dans Symfony&lt;/h3&gt;
&lt;p&gt;Si vous souhaitez utiliser React sur une partie de votre site seulement, il est possible d’intégrer vos composants React directement dans Twig.&lt;/p&gt;
&lt;p&gt;Reprenons notre exemple de la Todo List, nous avons donc nos répertoires &lt;code&gt;components&lt;/code&gt; contenant nos composants et &lt;code&gt;js&lt;/code&gt; contenant nos autres scripts et nos composants principaux dont le composant &lt;code&gt;TodoList&lt;/code&gt;. Lors du build, webpack (ou un autre task runner) va récupérer uniquement les composants enfants nécessaires (compris dans TodoList) ainsi que &lt;code&gt;index.js&lt;/code&gt; (on va y revenir un peu plus loin) et les compiler en un seul fichier : &lt;code&gt;todolist.js&lt;/code&gt;. On peut le résumer avec le schéma suivant :
&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/react-symfony/todo-list_component.1227d82e.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2017/react-symfony/todo-list_component.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 572px; ; aspect-ratio: calc(572 / 482)&quot; src=&quot;https://jolicode.com//media/cache/content/2017/react-symfony/todo-list_component.png&quot; alt=&quot;Todo list component&quot; title=&quot;archi component&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Ce fichier js compilé va ensuite être inclus dans notre template twig avec la balise &amp;lt;script&amp;gt; habituelle :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-10&quot;&gt;{# layout.html.twig #}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{% &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; body %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;        id&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;todolist&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;        data-items&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;{{ &lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;syntax-9&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; }}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    &gt;&amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{% &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;endblock&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{% &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; javascripts %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; type&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; src&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;{{ asset(&#039;todo-list.js&#039;) }}&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{% &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;endblock&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vous noterez la présence de la div &lt;code&gt;#todolist&lt;/code&gt; et l’attribut de données &lt;code&gt;data-items&lt;/code&gt; contenant la donnée &lt;code&gt;items&lt;/code&gt; encodée en json (passée par le Controller).&lt;/p&gt;
&lt;p&gt;Revenons sur le fichier &lt;code&gt;index.js&lt;/code&gt;, dans celui-ci nous allons créer notre Composant TodoList en lui passant la props &lt;code&gt;items&lt;/code&gt; qu&#039;on a récupéré de la data-items avec la fonction &lt;code&gt;getData&lt;/code&gt;. Enfin, on injecte ce composant au niveau de notre div &lt;code&gt;#todolist&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-10&quot;&gt;// index.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; React &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;react&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; ReactDOM &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;react-dom&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; TodoList &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; &#039;./TodoList.jsx&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; TodoListElement &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; document.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;#todo-list&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; getData&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt; true&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;    const&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; value &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; TodoListElement.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;`data-&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; json &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; JSON.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(value) &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; element &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; React.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(TodoList, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    items: &lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(items),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;ReactDOM.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(element, document.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;todo-list&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nous avons donc notre composant React dans notre fichier Twig.&lt;/p&gt;
&lt;p&gt;On part donc du postulat que le client de votre API (ici le navigateur) est capable d’interpréter du JavaScript, de manière fiable et performante, ce qui n’est pas toujours le cas ! On peut prendre l’exemple des crawlers qui parcourent vos pages Web pour indexer leur contenu dans les moteurs de recherche. Certains d’entre eux sont (encore à l’heure actuelle) incapable de comprendre votre code JavaScript et ne verront donc que des pages vides. Cas de figure plus fréquent, les utilisateurs qui consultent votre site via des appareils très peu puissants (smartphones de premières générations, ou même le vieil ordinateur de bureau de votre grand-mère), risquent de voir les performances du site fortement dégradés.&lt;/p&gt;
&lt;p&gt;Exemple de site vu par un robot qui n’indexe pas du javascript :&lt;/p&gt;
&lt;p style=&quot;width:50%; float:left;&quot;&gt;&lt;span style=&quot;display:block; text-align:center;&quot;&gt;Avec JavaScript&lt;/span&gt;&lt;picture class=&quot;js-dialog-target&quot; data-original-url=&quot;/media/original/2017/react-symfony/nojs_bienici_1.png&quot; data-original-width=&quot;1000&quot; data-original-height=&quot;826&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/react-symfony/nojs_bienici_1.3ecf5260.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2017/react-symfony/nojs_bienici_1.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;90%&quot; style=&quot;width: 996px; ; aspect-ratio: calc(1000 / 826); border: solid 1px #555&quot; src=&quot;https://jolicode.com//media/cache/content/2017/react-symfony/nojs_bienici_1.png&quot; alt=&quot;Bienici&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p style=&quot;width:50%; float:left;&quot;&gt;&lt;span style=&quot;display:block; text-align:center;&quot;&gt;Sans JavaScript&lt;/span&gt;&lt;picture class=&quot;js-dialog-target&quot; data-original-url=&quot;/media/original/2017/react-symfony/nojs_bienici_2.png&quot; data-original-width=&quot;1000&quot; data-original-height=&quot;823&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/react-symfony/nojs_bienici_2.a96745bb.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2017/react-symfony/nojs_bienici_2.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;90%&quot; style=&quot;width: 996px; ; aspect-ratio: calc(1000 / 823); border: solid 1px #555&quot; src=&quot;https://jolicode.com//media/cache/content/2017/react-symfony/nojs_bienici_2.png&quot; alt=&quot;Bienici&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;
&lt;p&gt;C’est là que le rendu serveur intervient.&lt;/p&gt;
&lt;h4&gt;Le rendu serveur&lt;/h4&gt;
&lt;p&gt;Avant de détailler notre dernière solution, il convient de parler un peu rendu serveur.&lt;/p&gt;
&lt;h5&gt;Kesako ?&lt;/h5&gt;
&lt;p&gt;Le rendu serveur, c’est donner à votre site la faculté de rendre les composants React… côté serveur. Concrètement, dans une application React classique, le serveur envoie à votre navigateur votre code React (transpilé en JavaScript et souvent compilé en un fichier), et c’est le navigateur qui va interpréter ce code, exécuter React, rendre vos composants, réagir aux actions de l’utilisateur, etc.
&lt;video src=&quot;https://jolicode.com//media/original/2017/react-symfony/post_serverside.mp4&quot; controls autoplay poster=&quot;/media/original/2017/react-symfony/post_serverside.gif&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Le rendu serveur vise donc à pallier les problèmes de référencement, de performance et d’affichage de contenu pour tous les utilisateurs.
Au lieu de renvoyer au navigateur votre code React, et de le laisser se débrouiller avec, le serveur génère lui-même le rendu HTML de vos composants et le renvoie au navigateur.&lt;/p&gt;
&lt;p&gt;Plusieurs technologies existent pour faire du rendu serveur :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un serveur node externe ;&lt;/li&gt;
&lt;li&gt;l’extension PHP V8JS ;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nous avons aussi la librairie PhpExecJS qui détecte automatiquement le moyen à utiliser pour exécuter le JS (V8JS ou Node). Pour en savoir plus sur ces technologies, nous vous renvoyons &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://jolicode.github.io/react-et-symfony-conf/?full#26&quot;&gt;aux slides de notre conférence&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;Rendu client, serveur ou les deux&lt;/h5&gt;
&lt;p&gt;Le problème de ce type de rendu est que votre code React devient invisible pour votre navigateur. Celui-ci n&#039;exécute aucun code JavaScript, et vous perdrez toute l’interactivité et la fluidité offerte par React. Le bouton qui faisait apparaître votre beau formulaire ne fonctionnera plus, de même que les filtres et les tris dans vos listes. Il faudra donc mettre en place des mécanismes alternatifs.&lt;/p&gt;
&lt;p&gt;Le mécanisme le plus souvent utilisé est de remplacer chaque interaction de votre code React par un lien, permettant de charger une nouvelle page avec les informations à jour. Le bouton &amp;quot;Ajouter&amp;quot; qui ouvrait votre formulaire devient un lien vers une page de création, le bouton &amp;quot;Trier par date&amp;quot; un lien avec la même URL que votre page courante, mais avec un paramètre précisant le tri souhaité, et ainsi de suite. Cette solution vous permet de conserver une certaine interactivité avec un rendu full-serveur.&lt;/p&gt;
&lt;p&gt;Comment ça full-server ? On peut faire du half-server ?&lt;/p&gt;
&lt;p&gt;Eh bien oui, c’est possible, on pourrait donc profiter de tous les avantages du rendu serveur (premier affichage plus rapide, page lisible par les robots, affichage de contenu pour tous, même sans JavaScript…) tout en conservant le dynamisme offert par React côte client. Il est donc extrêmement puissant sur le papier, mais pas forcément évident à mettre en place, et c’est là qu’intervient Limenius ReactBundle.&lt;/p&gt;
&lt;h3&gt;LimeniusReactBundle&lt;/h3&gt;
&lt;p&gt;La dernière solution que nous vous proposons est donc d’utiliser un bundle. Il en existe plusieurs à l’heure où nous écrivons, mais le seul à vraiment sortir du lot est &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/Limenius/ReactBundle&quot;&gt;Limenius ReactBundle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Basé sur &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/shakacode/react_on_rails&quot;&gt;React-on-Rails&lt;/a&gt;, ce bundle permet d’appeler vos composants React directement dans Twig, en exposant une extension Twig &lt;code&gt;react_component&lt;/code&gt;. Il utilise &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/nacmartin/phpexecjs&quot;&gt;PhpExecJS&lt;/a&gt; pour détecter l’environnement JavaScript installé sur vos serveurs (entre V8JS et Node) et utilise celui-ci.
Il définit également une extension permettant de gérer un store pour les projets utilisant redux. Enfin, il permet de préciser, via un simple paramètre, si vous souhaitez du rendu client uniquement, serveur uniquement ou les deux.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{{ react_component(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;HomePage&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, {&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;rendering&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;server_side&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;}) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{{ react_component(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;HomePage&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, {&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;rendering&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;client_side&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;}) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{{ react_component(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;HomePage&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, {&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;rendering&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;both&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;}) }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a donc :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;server_side&lt;/code&gt; : rendu du composant uniquement côté serveur.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;client_side&lt;/code&gt; :  rendu du composant uniquement côté client.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;both&lt;/code&gt; : rendu du composant client ET serveur.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour ce dernier choix, nous pouvons imaginer une page qui fonctionne de la manière suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le navigateur appelle votre serveur et lui demande d’afficher une liste d’utilisateurs.&lt;/li&gt;
&lt;li&gt;Le serveur interprète le code React et renvoie au client le HTML généré ET le code React.&lt;/li&gt;
&lt;li&gt;Le navigateur affiche le code HTML sans se poser de question puis commence à interpréter le code JavaScript.&lt;/li&gt;
&lt;li&gt;React, grâce à une variable JavaScript que le serveur a gentiment glissée dans le code généré, reconnaît le code HTML présent comme issu de vos composants.&lt;/li&gt;
&lt;li&gt;Il reconstruit un DOM virtuel basé sur ce que vous voyez à l’écran, sans toucher au HTML, et se &amp;quot;réapproprie&amp;quot; le code.&lt;/li&gt;
&lt;li&gt;React ayant repris la main sur l’affichage, vos boutons, filtres et autres joyeusetés reprennent le fonctionnement attendu.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce bundle nous permet donc d’écrire librement nos composants et d’appliquer un rendu serveur (ou non) uniquement sur les composants nécessaires. Le rendu serveur est utile mais assez coûteux niveau performance, l’ajout d’une feature-flag pour désactiver le rendu serveur peut être utile lors de très fortes affluences sur le site.&lt;/p&gt;
&lt;p&gt;Vous pouvez &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://jolicode.github.io/react-et-symfony-conf/?full#coverpage&quot;&gt;voir les slides&lt;/a&gt; et &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=ZpIg1AYgBcE&amp;amp;index=9&amp;amp;list=PL9zDdgiGjkIcl0_ZvVdH4GKCYL6OHZDTM&quot;&gt;la vidéo&lt;/a&gt; de notre conférence.&lt;/p&gt;
&lt;h2&gt;Références et bibliographie&lt;/h2&gt;
&lt;p&gt;Vous trouverez ici de la documentation et des articles intéressants pour approfondir sur ce sujet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/tutorial/tutorial.html&quot;&gt;react intro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/docs/components-and-props.html&quot;&gt;react composants et props&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/docs/state-and-lifecycle.html&quot;&gt;react state et lifecycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/docs/reconciliation.html&quot;&gt;react réconciliation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://redux.js.org/&quot;&gt;redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://redux-form.com/&quot;&gt;redux-form&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://redux-saga.js.org/&quot;&gt;redux-saga&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://knpuniversity.com/screencast/symfony/reactjs-api&quot;&gt;react avec une api symfony&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.codementor.io/tamizhvendan/beginner-guide-setup-reactjs-environment-npm-babel-6-webpack-du107r9zr&quot;&gt;webpack avec react&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://airbnb.io/enzyme/index.html&quot;&gt;tests react avec Enzyme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/marmelab/admin-on-rest&quot;&gt;admin-on-rest github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://api-platform.com/&quot;&gt;api-platorm&lt;/a&gt; et &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/api-platform/admin&quot;&gt;api-platform admin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/baywatch-d-angular-a-react-avec-une-dose-de-reactnative</id>
        <published>2017-02-14T12:00:00+01:00</published>
        <updated>2017-02-14T12:00:00+01:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/baywatch-d-angular-a-react-avec-une-dose-de-reactnative"/>
        <title>Baywatch : d&#039;Angular à React, avec une dose de ReactNative</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="react" />            <category term="baywatch" />            <category term="redux" />        <summary><![CDATA[Je n&#039;ai pas pu résister longtemps à l&#039;envie de réécrire l&#039;application Baywatch en React, notre application (et la vôtre) de partage de veille. La première version Angular, développée il y a 3 ans, était…]]></summary>
        <content type="html">
            &lt;p&gt;Je n&#039;ai pas pu résister longtemps à l&#039;envie de réécrire l&#039;application &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://baywatch.io/&quot; title=&quot;Baywatch&quot;&gt;Baywatch&lt;/a&gt; en React, notre application (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://baywatch.io/create&quot; title=&quot;et la vôtre&quot;&gt;et la vôtre&lt;/a&gt;) de partage de veille. La première version Angular, développée il y a 3 ans, était un petit sac de nœuds mélangeant plusieurs paradigmes d&#039;Angular: événement, factory, contrôleur, directives…&lt;/p&gt;
&lt;p&gt;Quelques semaines plus tard (~5), la refonte est terminée. Baywatch, tout beau tout neuf, tourne sur la triptyque huppée du moment : Webpack, React &amp;amp; Redux 💕.&lt;/p&gt;
&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;&lt;picture class=&quot;js-dialog-target&quot; data-original-url=&quot;/media/original/2017/baywatch/header-git.png&quot; data-original-width=&quot;2054&quot; data-original-height=&quot;310&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/baywatch/header-git.d7231fd0.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2017/baywatch/header-git.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 996px; ; aspect-ratio: calc(2054 / 310)&quot; src=&quot;https://jolicode.com//media/cache/content/2017/baywatch/header-git.png&quot; alt=&quot;La PR&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2&gt;Pourquoi une refonte ?&lt;/h2&gt;
&lt;p&gt;Cette refonte, purement technique, concerne uniquement l&#039;application Web (et non l&#039;API), sans ajouter, ni supprimer de fonctionnalités et tout en gardant le même design/markup. Le but était donc de remplacer Angular par React pour moderniser la stack et avoir une base de code attractive et maintenable.&lt;/p&gt;
&lt;p&gt;Je ne parle pas ici de migration car je n’ai réutilisé aucun code. Mais il est tout à fait possible de faire co-exister du code Angular et React, pour entreprendre une migration progressive. Celle-ci peut commencer par les feuilles de l’arbre applicatif puis remonter vers le tronc (le routeur en général), l&#039;article &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://tech.small-improvements.com/2017/01/25/how-to-migrate-an-angularjs-1-app-to-react&quot;&gt;&amp;quot;Our journey migrating 100k lines of code from AngularJS to React (Chapter 1)&amp;quot;&lt;/a&gt; détaille ce point-ci.&lt;/p&gt;
&lt;p&gt;Baywatch fonctionnait bien, mais l&#039;ajout de nouvelles fonctionnalités était compliqué avec Angular :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Base de code difficile et complexe ;&lt;/li&gt;
&lt;li&gt;Manque de motivation relatif à Angular ;&lt;/li&gt;
&lt;li&gt;Frustration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La courbe d&#039;apprentissage d&#039;Angular est assez élevée, notamment à cause de ses nombreux concepts : directives, services, factory, digest, filter et j&#039;en passe. Angular est un framework (contrairement à React qui est une librairie) et implique une compréhension de tous ces concepts.&lt;/p&gt;
&lt;p&gt;Voici ma “rage curve” pleine de mauvaise foi pour illustrer mon ressenti 🙃 :&lt;/p&gt;
&lt;p&gt;&lt;picture class=&quot;js-dialog-target&quot; data-original-url=&quot;/media/original/2017/baywatch/learning.jpg&quot; data-original-width=&quot;1111&quot; data-original-height=&quot;657&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/baywatch/learning.8ed83f02.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2017/baywatch/learning.jpg&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 996px; ; aspect-ratio: calc(1111 / 657)&quot; src=&quot;https://jolicode.com//media/cache/content/2017/baywatch/learning.jpg&quot; alt=&quot;Rage curve React/Angular&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;J&#039;ai découvert entre temps React et Redux, enterrant toute motivation de maintenir du code Angular. La courbe d&#039;apprentissage de React est plus légère. On assimile vite les quelques concepts inhérents à React : composants, state, props &amp;amp; JSX. Son API publique est simple et abstrait la complexité interne.&lt;/p&gt;
&lt;p&gt;Ce qui peut s&#039;avérer plus compliqué est l&#039;application des bonnes pratiques et concepts d&#039;architecture avancée (High order component, Redux, containers… ). Mais cet apprentissage se fait progressivement, contrairement à un Angular plus monolithique. Pour ceux qui voudraient commencer sur React, je conseille l’excellent &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebookincubator/create-react-app&quot;&gt;create-react-app&lt;/a&gt; permettant d’abstraire webpack/babel et se focaliser uniquement sur le code React.&lt;/p&gt;
&lt;h2&gt;On dépoussière la stack: Yarn, Webpack &amp;amp; Babel&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/baywatch/headers-icons.4c3ff879.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2017/baywatch/headers-icons.jpg&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 800px; ; aspect-ratio: calc(800 / 240)&quot; src=&quot;https://jolicode.com//media/cache/content/2017/baywatch/headers-icons.jpg&quot; alt=&quot;Bye&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yarn&lt;/strong&gt;
&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://yarnpkg.com/&quot;&gt;https://yarnpkg.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;L’ensemble des dépendances est géré par Yarn (et donc npm en coulisses). En plus du gain de vitesse lors de la résolution des dépendances, Yarn verrouille automatiquement les dépendances (byebye &lt;code&gt;npm shrinkwrap&lt;/code&gt;). Plus besoin également d’ajouter le &lt;code&gt;--save&lt;/code&gt; afin d&#039;ajouter la dépendance au &lt;code&gt;package.json&lt;/code&gt;. À noter quelques difficultés avec des dépendances Github (référence de commit, non taguées, fork).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Webpack 2&lt;/strong&gt;
&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://webpack.js.org/&quot;&gt;https://webpack.js.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Webpack s’occupe du build de l’application. Sous ses airs compliqués, cet outil est assez simple à prendre en main. Pour Baywatch, nous avons deux bundles compilés : un pour le code userland et l’autre pour les vendors :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;entry: {
 app: APP_MODULE,
 vendor: VENDOR_MODULES
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pensez à gérer dans votre config le build en mode production (UglifyJsPlugin, LoaderOptionPlugin…) et à utiliser &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/docs/installation.html#development-and-production-versions&quot;&gt;la version prod de React&lt;/a&gt;, les performances n’en seront que meilleures et les petites connexions internet vous remercieront 🐢.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;new webpack.DefinePlugin({
      &#039;process.env.NODE_ENV&#039;: JSON.stringify(&#039;production&#039;),
    }),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La migration vers la version 2 de Webpack n’est pas trop compliqué, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://webpack.js.org/guides/migrating/&quot;&gt;la nouvelle documentation&lt;/a&gt; est assez claire sur ce sujet. Je n’ai pas eu de gros gain au niveau de la taille des mes bundles malgré la promesse du &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://medium.freecodecamp.com/tree-shaking-es6-modules-in-webpack-2-1add6672f31b#.m156pwvff&quot;&gt;tree-shaking&lt;/a&gt; 😢.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Babel&lt;/strong&gt;
&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://babeljs.io/&quot;&gt;https://babeljs.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Babel permet de débloquer ✌ la syntaxe ES5/6 ✌ :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names&quot;&gt;Computed property name&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;Arrow function&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/sebmarkbage/ecmascript-rest-spread/blob/master/Spread.md&quot;&gt;Object Spread Initializer&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cet ensemble de nouvelles syntaxes permet de livrer un code moins verbeux. Attention à ne pas trop en abuser, cela peux vite déboucher sur un code trop méta (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://medium.com/@sAbakumoff/es6-is-great-until-its-not-f398339d0af6#.2c3mkfhtw&quot;&gt;&amp;quot;ES6 is great, but use it cautiously&amp;quot;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;👉 &lt;em&gt;Note sur Babel et Webpack 2&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;La version 1 de Webpack n’était pas capable de parser des modules ES6, c’est pourquoi Babel les convertit en module CommonJS. En effet lorsque vous renseignez dans votre &lt;code&gt;.babelrc&lt;/code&gt; le preset &lt;code&gt;es2015&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  &quot;presets&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-15&quot;&gt;    &quot;es2015&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Celui-ci a pour défaut &lt;code&gt;commonjs&lt;/code&gt; comme type de module (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://babeljs.io/docs/plugins/preset-es2015/#options&quot;&gt;cf. la doc de Babel&lt;/a&gt;). Bonne nouvelle, Webpack 2 est maintenant capable de parser des modules ES6, il n’est donc plus utile de les convertir en CommonJS. Pour désactiver la conversion, il suffit de passer le flag &lt;code&gt;modules&lt;/code&gt; à &lt;code&gt;false&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  &quot;presets&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;es2015&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;&quot;modules&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En plus du gain de vitesse lors du build, Webpack peut désormais détecter les blocs de code morts et les retirer de vos bundles (cf. tree-shaking).&lt;/p&gt;
&lt;h2&gt;React &amp;amp; co&lt;/h2&gt;
&lt;p&gt;Les raisons concernant le choix de React ont été évoquées plus haut, je vais détailler ici les librairies utilisées conjointement avec React. La première, indispensable, est la fameuse librairie Redux.&lt;/p&gt;
&lt;h3&gt;Redux&lt;/h3&gt;
&lt;p&gt;React est une librairie et non un framework. Sans autre outil que React, il est difficile de rendre une application maintenable et scalable. Dès que le nombre de composants augmente, on tombe vite dans les méandres des callbacks passés via les props, ou on commence à utiliser &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react/docs/context.html&quot;&gt;le context&lt;/a&gt; à tout va. Il en est de même pour les données applicatives, souvent éclatées au travers des composants.&lt;/p&gt;
&lt;p&gt;Pour répondre à ce problème, Facebook a créé une spécification et son implémentation : Flux. J’utilise une des implémentations les plus connues : &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://redux.js.org/&quot;&gt;Redux&lt;/a&gt;. Il en existe d’autres, mais Redux s’est imposée (à juste titre) comme la référence. Cette librairie est pour moi indispensable dès qu&#039;une application contient plus de 3-4 composants. Une fois maîtrisée (ce qui passe par beaucoup de veille technique), elle désamorce en grande partie la complexité d&#039;une application : le workflow est clair, rodé, et satisfait 95% des cas d&#039;utilisation.&lt;/p&gt;
&lt;h3&gt;Redux permet de mettre en place très facilement des patterns favorisant l’expérience utilisateur&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Exploiter le LocalStorage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Redux apporte le concept du ✨ single source of truth ✨, vos données sont stockées dans un seul et même objet javascript. Baywatch utilise la librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/rt2zz/redux-persist&quot;&gt;redux-persist&lt;/a&gt; permettant de synchroniser facilement une partie de votre store avec votre LocalStorage et ainsi d’améliorer la performance et l&#039;expérience utilisateur.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const store = createStore(
  reducer,
  undefined,
  compose(
    applyMiddleware(...),
    autoRehydrate()
  )
)

// Begin periodically persisting the store
persistStore(store)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2017/baywatch/localstorage.4df37eed.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2017/baywatch/localstorage.jpg&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 800px; ; aspect-ratio: calc(800 / 183)&quot; src=&quot;https://jolicode.com//media/cache/content/2017/baywatch/localstorage.jpg&quot; alt=&quot;LocalStorage&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Undo/redo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mettre en place un système de undo/redo est chose aisée grâce à l’architecture propre de Redux. Toutes les interactions passent par les reducers, et on peut ainsi garder facilement un historique de l’état du store pour naviguer dans le temps. La librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/omnidan/redux-undo&quot;&gt;redux-undo&lt;/a&gt; permet d’implémenter facilement ce pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optimistic UI&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Grâce à Redux, on peut facilement mettre en place le pattern &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.smashingmagazine.com/2016/11/true-lies-of-optimistic-user-interfaces/&quot;&gt;optimistic UI&lt;/a&gt;. Dans 95% des cas, notre API va retourner les données attendues. On peut donc mettre à jour notre UI pour signaler que l’opération s’est bien déroulée sans même attendre la réponse. Baywatch utilise ce pattern pour augmenter sensiblement la vitesse perçue par l’utilisateur.&lt;/p&gt;
&lt;p&gt;Une action asynchrone permettant d’ajouter en favoris un bookmark se sépare en 3 états :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⏳ ADD_FAVORITE_PENDING
✅ ADD_FAVORITE_SUCCESS
🚫 ADD_FAVORITE_ERROR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On peut dès l’action &lt;code&gt;ADD_FAVORITE_PENDING&lt;/code&gt; mettre à jour notre interface pour signaler l’ajout en favoris (passer l’étoile en jaune ⭐️ par exemple). Deux cas se présentent ensuite :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ADD_FAVORITE_SUCCESS&lt;/code&gt;: cas attendu, tout s’est bien passé on ne fait
rien ✅ ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ADD_FAVORITE_ERROR&lt;/code&gt;: pas de chance, on repasse l’étoile dans son
état initial ☹️.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Communication avec son API&lt;/h2&gt;
&lt;p&gt;La complexité réside souvent dans le couplage avec l’API : comment récupérer les données, à quel niveau ? La bonne pratique est de créer un middleware Redux pour gérer les appels. Chaque appel asynchrone se divise en 3 actions élémentaires :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⏳ LOAD_BOOKMARKS_PENDING
✅ LOAD_BOOKMARKS_SUCCESS
🚫 LOAD_BOOKMARKS_ERROR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;L&#039;action &lt;code&gt;PENDING&lt;/code&gt; envoie la requête vers le serveur puis selon la résolution de la promesse, les actions correspondantes sont lancées (&lt;code&gt;SUCCESS&lt;/code&gt; ou &lt;code&gt;ERROR&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;La librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/svrcekmichal/redux-axios-middleware&quot;&gt;redux-axios-middleware&lt;/a&gt; permet de faciliter la mise en place d’un tel mécanisme. J’utilise souvent le client HTTP &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/mzabriskie/axios&quot;&gt;Axios&lt;/a&gt; car il propose des fonctionnalités intéressantes telles que les intercepteurs ou l’annulation de requête (contrairement à &lt;code&gt;fetch&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const client = axios.create({
  baseURL:&#039;http://localhost:8080/api&#039;,
  responseType: &#039;json&#039;
});

let store = createStore(
  reducers, //custom reducers
  applyMiddleware(
    ...
    axiosMiddleware(client),
    ...
  )
)

export function loadBookmarks() {
  return {
    types: [LOAD_BOOKMARK_PENDING, LOAD_BOOKMARK_SUCCESS, LOAD_BOOKMARK_FAIL],
    normalize: true,
    payload: {
      request:{
        url:&#039;/bookmarks&#039;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Les intercepteurs permettent d’injecter la logique due à l’authentification (token JWT, erreurs 401, préfixe de l&#039;API…) :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interceptors: {
    request: [({getState}, config) =&amp;gt; {
       let { auth } = getState()
       if (auth.token) {
         config.params.access_token = auth.token
       }

       return config
     }],
   },
   onError: ({ error, next, action }, options) =&amp;gt; {
     const {status} = error.response
     if (status === 401) {
       next(push(&#039;/login&#039;))
       next(logoutUser())
     }

     return defaultOnError({action, next, error}, options)
   }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Attention tout de même : la dernière version comporte un bug lié aux intercepteurs, qui a été corrigé &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/svrcekmichal/redux-axios-middleware/pull/38&quot;&gt;dans la PR&lt;/a&gt; de mon collègue Thibault.&lt;/p&gt;
&lt;h3&gt;Normalisation des données&lt;/h3&gt;
&lt;p&gt;Lors de la construction d’une application, l’erreur fréquente est de stocker les données d’API en l’état dans ses stores Redux. Or, leur schéma n’est généralement pas optimal pour l’utiliser dans React. Il est important de passer par une étape de normalisation afin d’avoir un &lt;code&gt;state&lt;/code&gt; optimal et facilement exploitable. Si votre API retourne une liste de ressources telle que :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  &quot;bookmarks&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      {&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;122&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-13&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;http://link1.io&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      {&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-13&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;http://link2.io&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La recherche sera coûteuse. La bonne pratique est d&#039;indiquer les identifiants des ressources en clé :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;    &quot;bookmarks&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;        &quot;122&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;122&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-13&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;http://link1.io&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;        &quot;123&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-13&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;http://link2.io&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ainsi, vous pouvez accéder directement à l&#039;élément sans le rechercher (complexité constante &lt;code&gt;O(1)&lt;/code&gt; contre complexité linéaire &lt;code&gt;O(n)&lt;/code&gt;).&lt;/p&gt;
&lt;p style=&quot;text-align: center&quot;&gt;✌🔥✨🔥✨🔥✨
&lt;b&gt;much math  ✨✨✨ many skill such WOW&lt;/b&gt;
✨🔥✨🔥✨🔥✌&lt;/p&gt;
&lt;p&gt;Il est également important de ne pas dupliquer vos données dans votre state (c&#039;est-à-dire stocker des identifiants plutôt que des entités dupliquées au travers des stores) et éviter les structures imbriquées :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-10&quot;&gt;// 👎&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  &quot;boookmarks&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;    &quot;id&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;    &quot;url&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;https://joli.beer/&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;    &quot;author&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;      &quot;uid&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;      &quot;username&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;shinework&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-10&quot;&gt;// 👍&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  &quot;boookmarks&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-13&quot;&gt;    123&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;      &quot;url&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;https://joli.beer/&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;      &quot;authorUid&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;  &quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-13&quot;&gt;    37&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;      &quot;username&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;shinework&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pour gérer ces problématiques, j’ai utilisé la librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/paularmstrong/normalizr&quot;&gt;Normalizr&lt;/a&gt; permettant de définir des schémas de normalisation. Je n’ai eu qu’à les utiliser dans l’intercepteur de mon client HTTP pour appliquer les transformations sur la réponse de mon API :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interceptors: {
   response: [({getAction}, response) =&amp;gt; {
     const action = getAction()
     return (action.normalize &amp;amp;&amp;amp; response.data) ? normalize(response.data, ApiSchema) : response
   }],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;L&#039;excellent article &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://hackernoon.com/avoiding-accidental-complexity-when-structuring-your-app-state-6e6d22ad5e2a#.735abuler&quot;&gt;&amp;quot;Avoiding Accidental Complexity When Structuring Your App State&amp;quot;&lt;/a&gt; détaille cette problématique en quelques préceptes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Éviter de modéliser votre state selon ce que retourne votre API ;&lt;/li&gt;
&lt;li&gt;Éviter de modéliser votre state selon ce que qu’affichent vos composants ;&lt;/li&gt;
&lt;li&gt;Préférer les maps aux tableaux ;&lt;/li&gt;
&lt;li&gt;Ne pas dupliquer vos données dans votre state ;&lt;/li&gt;
&lt;li&gt;Ne pas dériver des données (utiliser des &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://redux.js.org/docs/recipes/ComputingDerivedData.html&quot;&gt;sélecteurs&lt;/a&gt;) ;&lt;/li&gt;
&lt;li&gt;Normaliser vos données.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Architecture&lt;/h2&gt;
&lt;h3&gt;Architecture globale&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;├── src/
│   ├── actions/
│   ├── api/
│   ├── assets/
│   ├── components/
│   ├── constants/
│   ├── containers/
│   ├── models/
│   ├── reducers/
│   ├── store/
│   ├── translations/
│   └── utils/
│   ├── config.js
│   ├── routes.js
│   ├── shortcuts.js
│   ├── app.js
│.babelrc
│package.json
│webpack.config.js
│yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C&#039;est une architecture récurrente d’une application Redux. L&#039;ensemble de la stack Redux se trouve dans les répertoires &lt;code&gt;actions&lt;/code&gt;, &lt;code&gt;reducers&lt;/code&gt;, &lt;code&gt;store&lt;/code&gt;, &lt;code&gt;constants&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Le répertoire &lt;code&gt;api&lt;/code&gt; contient mes schémas propres à &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/paularmstrong/normalizr&quot;&gt;normalizr&lt;/a&gt; et mon instance du client http axios.&lt;/p&gt;
&lt;p&gt;A noter qu’il existe une autre architecture orientée fonctionnalités (je ne l’ai personnellement pas encore testé). Celle-ci a pour avantage de regrouper les fichiers par fonctionnalités (composants, reducers, actions…) rendant la navigation plus aisée.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;├── src/
│   ├── bookmarks/
│            ├── bookmarkReducer.js
│            ├── bookmarkActions.js
│            ├── bookmarksContainer.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Je pense que cela à du sens, l’article “&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://medium.com/@alexmngn/how-to-better-organize-your-react-applications-2fd3ea1920f1#.lhjkxzwvl&quot;&gt;How to better organize your React applications&lt;/a&gt;” détaille cette architecture.&lt;/p&gt;
&lt;h3&gt;Dépendances de Baywatch (hors développement)&lt;/h3&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;axios&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^0.15.2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;clipboard&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^1.5.16&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;history&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^3.0.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;immutable&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^3.8.1&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;jwt-decode&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^2.1.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;lodash&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^4.17.2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;moment&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^2.17.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;normalizr&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^2.2.1&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;notie&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^3.9.5&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^15.4.2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-dom&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^15.4.2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-dropzone&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^3.8.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-infinite-scroller&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^1.0.4&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-redux&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^4.4.6&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-router&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^3.0.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-router-redux&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^4.0.7&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-select&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^1.0.0-rc.2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-shortcuts&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^1.3.1&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;react-translate&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^5.0.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;redux&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^3.1.2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;redux-auth-wrapper&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^0.9.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;redux-axios-middleware&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^0.3.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;redux-persist&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^4.0.1&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;redux-persist-transform-immutable&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^4.1.0&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt; &quot;redux-thunk&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-15&quot;&gt;&quot;^1.0.3&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Routing / firewall&lt;/h3&gt;
&lt;p&gt;Sans surprise, j’ai utilisé &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/ReactTraining/react-router&quot;&gt;react-router&lt;/a&gt; pour gérer le routing. Mes routes n’exposent que des composants “containers” (cf. ci-dessous). Afin de gérer facilement le firewall au niveau de mes routes, j’ai utilisé la librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/mjrussell/redux-auth-wrapper&quot;&gt;redux-auth-wrapper&lt;/a&gt;. Celle-ci permet de définir des prédicats sous forme de HOC autorisant ou non l’accès aux routes :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state =&amp;gt; state.auth,
  predicate: auth =&amp;gt; auth.token,
  wrapperDisplayName: &#039;UserIsAuthenticated&#039;,
  failureRedirectPath: &#039;/login&#039;
})

// Dans le routeur
&amp;lt;Route component={UserIsAuthenticated(AppContainer)}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Elle permet aussi de gérer facilement le mécanisme de redirection sur la route initiale après la connexion:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://team.baywatch.io/login?redirect=/all&quot;&gt;https://team.baywatch.io/login?redirect=/all&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Composants containers / présentations&lt;/h3&gt;
&lt;p&gt;L&#039;architecture &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0&quot;&gt;smart/dumb components&lt;/a&gt; permet de séparer la logique des composants en deux types:&lt;/p&gt;
&lt;p&gt;Composants &lt;strong&gt;container&lt;/strong&gt; constitués de la logique métier (&lt;em&gt;ce que fait l’application&lt;/em&gt; 🔧):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Appel des actions / handler ;&lt;/li&gt;
&lt;li&gt;Récupération des données ;&lt;/li&gt;
&lt;li&gt;Connexion aux stores Redux ;&lt;/li&gt;
&lt;li&gt;Composant &amp;quot;factory&amp;quot; ou &amp;quot;wrapper&amp;quot;, pour factoriser des comportements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Composants de &lt;strong&gt;présentation&lt;/strong&gt; (&lt;em&gt;ce qu’affiche l’application&lt;/em&gt; 🖼):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Composants applicatifs (“widgets”) ;&lt;/li&gt;
&lt;li&gt;Composants “purs” ;&lt;/li&gt;
&lt;li&gt;UI / Markup / CSS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ceci dans le but de séparer au mieux les concepts et de rendre les composants de présentation réutilisables avec des données variées.&lt;/p&gt;
&lt;p&gt;En pratique avec Redux, les composants de types &lt;strong&gt;container&lt;/strong&gt; se composent généralement d&#039;un &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options&quot;&gt;connect&lt;/a&gt; avec la définition des &lt;code&gt;mapStateToProps&lt;/code&gt; et &lt;code&gt;mapDispatchToProps&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {connect} from &#039;react-redux&#039;
import GroupHeader from &#039;./../components/GroupHeader&#039;
import {joinGroup, leaveGroup, askGroupInvitation} from &#039;./../actions/groups&#039;

const mapStateToProps = (state, props) =&amp;gt; {
  return {
    group: props.group,
    isPending: state.groups.isPending,
  }
}

const mapDispatchToProps = {
  leaveGroup,
  joinGroup,
  askGroupInvitation,
}

export default connect(mapStateToProps, mapDispatchToProps)(GroupHeader)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Les fonctions passées à &lt;code&gt;connect&lt;/code&gt; via l’objet &lt;code&gt;mapDispatchToProps&lt;/code&gt; vont être automatiquement appelées avec la méthode &lt;code&gt;dispatch&lt;/code&gt; (ex. &lt;code&gt;dispatch(leaveGroup())&lt;/code&gt;). Ainsi les composants &lt;strong&gt;dumb&lt;/strong&gt; pourront appeler ces fonctions depuis leurs &lt;code&gt;props&lt;/code&gt; sans se soucier de la logique de Redux.&lt;/p&gt;
&lt;p&gt;La fonction &lt;code&gt;mapStateToProps&lt;/code&gt; va quant à elle lier le state avec mon composant. À chaque modification du state, mes composants vont donc être re-rendus.&lt;/p&gt;
&lt;p&gt;À noter que la méthode &lt;code&gt;connect&lt;/code&gt; va automatiquement vérifier si les propriétés passées en &lt;code&gt;props&lt;/code&gt; ont changé et effectuer un rendu ou non :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[pure] (Boolean): If true, connect() will avoid re-renders and calls to mapStateToProps, mapDispatchToProps, and mergeProps if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: true&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Et le mobile ?&lt;/h2&gt;
&lt;div style=&quot;float: right; width: 260px; margin-left: 10px;margin-bottom: 10px&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; class=&quot;giphy-embed&quot; frameborder=&quot;0&quot; height=&quot;430&quot; src=&quot;//giphy.com/embed/l0EwYsFzPgyGtr0nS&quot; width=&quot;240&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Nous avons commencé un &lt;abbr title=&quot;Proof Of Concept&quot;&gt;POC&lt;/abbr&gt; d&#039;une application mobile pour Baywatch avec &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react-native/&quot;&gt;React Native&lt;/a&gt;, le but étant de valider la possibilité de réutiliser la stack Redux utilisée dans la webapp, à savoir :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les actions ;&lt;/li&gt;
&lt;li&gt;Les reducers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et ce fut un succès : nous avons pu développer uniquement les composants propres à React Native et développer très rapidement les fonctionnalités de base ✌.&lt;/p&gt;
&lt;h3&gt;Partage de la stack Redux entre web &amp;amp; mobile&lt;/h3&gt;
&lt;p&gt;La principale difficulté était donc d&#039;exposer les répertoires &lt;code&gt;actions&lt;/code&gt;, &lt;code&gt;reducers&lt;/code&gt;, &lt;code&gt;constants&lt;/code&gt; à notre projet React Native.&lt;/p&gt;
&lt;p&gt;Première hypothèse : mettre l&#039;application mobile et Web dans le même répertoire afin qu&#039;elles partagent le même &lt;code&gt;package.json&lt;/code&gt;. Mais cette méthode semble difficilement maintenable : on souhaite pouvoir changer indépendamment la version de React (ou autres librairies) sur les deux applications, chose impossible avec un &lt;code&gt;package.json&lt;/code&gt; commun.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;├── apps/
│   ├── mobile/
│   ├── web/
│   ├── node_modules/
│   ├── package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deuxième hypothèse : avoir deux &lt;code&gt;package.json&lt;/code&gt; pour chaque projet, ce qui semble le plus propre :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;├── webapp/
│   ├── src/
│   ├── node_modules/
│   ├── package.json
├── mobileapp/
│   ├── src/
│   ├── node_modules/
│   ├── index.ios.js
│   ├── index.android.js
│   ├── package.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cette architecture semble correcte mais apporte un nouveau problème : on ne peut pas importer de fichiers d&#039;un répertoire plus bas dans l&#039;arborescence que le fichier &lt;code&gt;package.json&lt;/code&gt;. Ainsi, impossible depuis le code de l&#039;application mobile d&#039;appeler notre stack Redux présente dans le répertoire webapp :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {loadBookmarks} from &#039;./../../webapp/src/&#039;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La solution idéale serait donc de créer un package à part, dédié à la stack Redux, qu&#039;on ajoute aux dépendances de nos deux applications :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {loadBookmarks} from &#039;baywatch-core&#039;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mais cela rend notre développement un peu plus laborieux. Pour l’heure, nous avons donc fait le choix d’une solution intermédiaire, en copiant simplement le répertoire &lt;code&gt;src&lt;/code&gt; de notre application web dans le répertoire &lt;code&gt;node_modules&lt;/code&gt; de notre application mobile. React Native ne supportant pas encore les liens symboliques, nous avons utilisé un outil publié par Wix afin de palier à ce problème : &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/wix/wml&quot;&gt;https://github.com/wix/wml&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wml add ../webapp/src/ ./node_modules/baywatch
wml start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ce qui nous permet bien d&#039;importer nos actions :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import {loadBookmarks} from &#039;baywatch/actions/bookmarks&#039;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On attend donc avec impatience &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/react-native/issues/637&quot;&gt;le support des liens symboliques&lt;/a&gt; avec React Native pour éviter ce hack disgracieux 🤓.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Il y a encore beaucoup de sujets à aborder sur cette refonte et le développement d&#039;application React :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;L&#039;utilisation de &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/immutable-js&quot;&gt;immutable.js&lt;/a&gt; avec Redux ;&lt;/li&gt;
&lt;li&gt;L&#039;utilisation de &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/reactjs/reselect&quot;&gt;sélecteurs&lt;/a&gt; et la mémoïsation ;&lt;/li&gt;
&lt;li&gt;Les leviers de performances avec l’optimisation des rendus ;&lt;/li&gt;
&lt;li&gt;L&#039;intégration avec une application Symfony ;&lt;/li&gt;
&lt;li&gt;Les tests avec &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt;, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/airbnb/enzyme&quot;&gt;Enzyme&lt;/a&gt;, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/avajs/ava&quot;&gt;Ava&lt;/a&gt;….&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;De manière générale, cette refonte a clarifié la base de code en supprimant quelques 8 000 lignes de codes. Il est aujourd&#039;hui plus facile de maintenir l&#039;application grâce à la scalabilité apportée par React &amp;amp; Redux. En désamorçant la complexité, ces librairies permettent de mieux se concentrer sur le détail applicatif permettant de délivrer des applications plus raffinées.&lt;/p&gt;
&lt;p&gt;N&#039;hésitez pas à nous contacter pour échanger sur des détails d&#039;architecture ou d&#039;implémentation. Vous nous trouverez aussi aux meetups React 🍻. Enfin, si vous êtes soucieux de votre veille et voulez la partager avec le reste de vos collègues, n’hésitez pas à tester &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://baywatch.io&quot;&gt;Baywatch&lt;/a&gt;. Tout feedback est le bienvenu.&lt;/p&gt;
&lt;p&gt;❤️🏄&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/starting-a-mobile-application-with-react-native</id>
        <published>2016-09-23T11:30:00+02:00</published>
        <updated>2016-09-23T11:30:00+02:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/starting-a-mobile-application-with-react-native"/>
        <title>Starting a mobile application with React Native</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="javascript" />            <category term="react" />            <category term="react-native" />        <summary><![CDATA[While preparing our next React Native training, I learnt a lot on the library and discovered an amazing community with a lot of packages. I felt the need to share the treasures I found.
How to start your…]]></summary>
        <content type="html">
            &lt;p&gt;While preparing our next &lt;a href=&quot;https://jolicampus.com/formations/react-native&quot;&gt;React Native&lt;/a&gt; training, I learnt a lot on the library and discovered an amazing community with a lot of packages. I felt the need to share the treasures I found.&lt;/p&gt;
&lt;h2&gt;How to start your project&lt;/h2&gt;
&lt;p&gt;There are already many ways to start your project, the simplest and official way is with &lt;code&gt;react-native-cli&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;react-native init AwesomeProject&lt;/code&gt; will generate all the project files needed to start with iOS and Android platforms (ex: Xcode and Gradle configurations).&lt;/p&gt;
&lt;p&gt;What if you need more ? Lucky you, I found three starter kits to bootstrap your project! Here are some explanations on each one, to help you choose the right one for your need. Be careful, they come with technical choices and some boilerplate code that you may not need.&lt;/p&gt;
&lt;h3&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/bartonhammond/snowflake&quot;&gt;Snowflake&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Highly focused on testing and CI, this one comes with nice video tutorials to guide you through. The author explains his choices and help you understand the redux architecture. I find this a really good template to begin with.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/snowflake.53b89c2c.webp&quot; /&gt;&lt;source type=&quot;image/gif&quot; srcset=&quot;/media/cache/content/2016/snowflake.gif&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 262px; ; aspect-ratio: calc(262 / 480); width: 350px&quot; src=&quot;https://jolicode.com//media/cache/content/2016/snowflake.gif&quot; alt=&quot;Snowflake&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/futurice/pepperoni-app-kit&quot;&gt;Pepperoni&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inspired from Snowflake with even more tools, like Auth0 integration, multi-environment configuration or Enzyme for testing. More advanced than Snowflake but also less accessible.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/pepproni.89eace68.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2016/pepproni.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 375px; ; aspect-ratio: calc(375 / 667); width: 350px&quot; src=&quot;https://jolicode.com//media/cache/content/2016/pepproni.png&quot; alt=&quot;Pepperoni&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/infinitered/ignite&quot;&gt;Ignite&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This one comes with generators that can help you iterate more quickly. Again, it is more complex than the others, with libs included (ie. react-native-maps) and another test mechanism built with &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/avajs/ava&quot;&gt;AVA&lt;/a&gt;. I recommend this one for advanced users.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/ignite.65c2cc3e.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2016/ignite.jpg&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 640px; ; aspect-ratio: calc(640 / 1136); width: 350px&quot; src=&quot;https://jolicode.com//media/cache/content/2016/ignite.jpg&quot; alt=&quot;Ignite&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3&gt;Architecture and navigation&lt;/h3&gt;
&lt;p&gt;All the previous starter kits are using Redux, this is a nice choice with React and it helps a lot managing the state of your application. The new &lt;code&gt;NavigatorExperimental&lt;/code&gt; merged in React Native is already using reducers to handle the navigation state.&lt;/p&gt;
&lt;p&gt;But this is not mandatory and you could just build your app without it, for example just using &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://jaketrent.com/post/smart-dumb-components-react/&quot;&gt;smart and dumb components&lt;/a&gt;, with the stateful Navigator component.&lt;/p&gt;
&lt;p&gt;I think the main difficulty when implementing the navigation is the number of choices available. To help you with that, I&#039;ll try to clarify each of the navigation options.&lt;/p&gt;
&lt;h4&gt;NavigatorIOS&lt;/h4&gt;
&lt;p&gt;The first option is a fully native one, only for iOS, sadly. It leverages the &lt;code&gt;UIViewController&lt;/code&gt; to handle the navigation stack and the transition. This is the way to go if you are building only for iOS and you want to feel as close as possible to the system UI. Since the stack is handled natively, you could run into problems when trying to manage it on the JS side. It is also less customizable than the others.&lt;/p&gt;
&lt;h4&gt;Navigator&lt;/h4&gt;
&lt;p&gt;This navigation component is built only with JS and so is completely cross platform and customizable. Since all transitions are built in JS, opening a heavy page could lead to FPS drop and degrade the experience. The library proposes an &lt;code&gt;InteractionManager&lt;/code&gt; to avoid doing work when transitioning with a method &lt;code&gt;runAfterInteractions&lt;/code&gt; but keep in mind that this delays the render of your new scene. This component is also stateful, unlike the next one...&lt;/p&gt;
&lt;h4&gt;NavigationExperimental&lt;/h4&gt;
&lt;p&gt;As the name tells you, this one is experimental and varies across releases. Fortunately, @jlyman is keeping an &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/jlyman/RN-NavigationExperimental-Redux-Example&quot;&gt;updated repo&lt;/a&gt; after each release with the implementations.&lt;/p&gt;
&lt;p&gt;NavigationExperimental relies on redux to handle the state and modify the navigation stack, this is the way to go if you want all your app to be managed by it. It needs more boilerplate code to start with but @jlyman and the official documentation will satisfy your copypasta addiction.&lt;/p&gt;
&lt;h4&gt;react-native-navigation&lt;/h4&gt;
&lt;p&gt;The last option is available as a module, and mentioned in the documentation page of NavigatorIOS. It provides a native navigation for both platforms and can be used with Redux! Since the navigation state is on the native side, the installation process involves editing the entry point and adding some boilerplate code in Objective-C and Java. The Android part is still a work in progress but I tried the examples and they all work really well. This is the way to go if you want to be as close as possible with the native UI and animation of the platforms.&lt;/p&gt;
&lt;h2&gt;Must have library&lt;/h2&gt;
&lt;p&gt;A lot of my research was into looking for the best components we could use to build our apps. Here is a tiny list of native and pure Javascript libraries for your development.&lt;/p&gt;
&lt;h3&gt;Javascript libraries&lt;/h3&gt;
&lt;p&gt;Since we are not in a browser context nor a nodejs context, library using window, document or node modules will not work. Here is a short list of the ones I find interesting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://momentjs.com/&quot;&gt;MomentJS&lt;/a&gt;: fully featured date and time library&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://underscorejs.org/&quot;&gt;UnderscoreJS&lt;/a&gt; / &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://lodash.com/&quot;&gt;lodash&lt;/a&gt;: toolkit to manipulate arrays, objects, strings...&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/immutable-js/&quot;&gt;ImmutableJS&lt;/a&gt;: immutable collections implementation&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/gaearon/redux-thunk&quot;&gt;Redux thunk&lt;/a&gt;, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/yelouafi/redux-saga&quot;&gt;redux saga&lt;/a&gt;: handling of asynchronous actions with Redux&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;React Native libraries&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/FaridSafi/react-native-gifted-listview&quot;&gt;react-native-gifted-listview&lt;/a&gt;: list enhancement with pull to refresh and load more capability&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/FaridSafi/react-native-gifted-form&quot;&gt;react-native-gifted-form&lt;/a&gt;: many form widgets and customization&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/skv-headless/react-native-scrollable-tab-view&quot;&gt;react-native-scrollable-tab-view&lt;/a&gt;: tabs navigation&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/gaearon/redux-devtools&quot;&gt;redux devtools&lt;/a&gt;, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/reactotron/reactotron&quot;&gt;reactotron&lt;/a&gt;: debug tools for Redux, time travel, logs and dispatching actions manually&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/root-two/react-native-drawer&quot;&gt;react-native-drawer&lt;/a&gt;: drawer navigation built only with JS&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/react-native-community/react-native-elements&quot;&gt;react-native-elements&lt;/a&gt;: nice UI toolkit for faster development&lt;/li&gt;
&lt;li&gt;Many many more… see &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://js.coach/&quot;&gt;js.coach&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Test your app (or not)&lt;/h2&gt;
&lt;p&gt;Testing is at your discretion but the tooling is ready and waiting for you!&lt;/p&gt;
&lt;p&gt;The official way seems to be Jest which provides mocks for React Native and a nice feature called Snapshot which allow developers to write fast tests to validate a component tree over time.&lt;/p&gt;
&lt;p&gt;I saw other implementations using Enzyme and &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/lelandrichardson/react-native-mock&quot;&gt;react-native-mock&lt;/a&gt;, closer to the ReactJS way. A good start is to look at the &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://airbnb.io/enzyme/docs/guides/react-native.html&quot;&gt;official implementation example by Airbnb&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { View, Text, StyleSheet } from &#039;react-native&#039;;
import { shallow } from &#039;enzyme&#039;;
import MyComponent from &#039;../src/MyComponent&#039;;
import { expect } from &#039;chai&#039;;

describe(&#039;&amp;lt;MyComponent /&amp;gt;&#039;, () =&amp;gt; {
  it(&#039;should render stuff&#039;, () =&amp;gt; {
    const wrapper = shallow(&amp;lt;MyComponent /&amp;gt;);
    expect(wrapper.length).to.equal(1);
    expect(wrapper.contains(&amp;lt;Text&amp;gt;I wonder if there will be any problems...&amp;lt;/Text&amp;gt;)).to.equal(true);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This covers up for unit testing in JS but you can also create functional tests, for this I tried Appium. This is an open source client-server software for manipulating simulator and device, the fun part is that the driver is implemented in many languages so you can write your tests also with JS and node. There is also a GUI to select manually the elements and generate boilerplate code.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/appium.80671918.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2016/appium.jpg&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 638px; ; aspect-ratio: calc(638 / 479)&quot; src=&quot;https://jolicode.com//media/cache/content/2016/appium.jpg&quot; alt=&quot;Alt text&quot; title=&quot;Appium&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2&gt;Deployment&lt;/h2&gt;
&lt;h3&gt;Assets&lt;/h3&gt;
&lt;p&gt;A tedious task when releasing an app is to create icons, images and splash screens for each device and platform. When using Titanium, we used Ticons which is a good cli library to integrate in your workflow and it also available as a website on &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://ticons.fokkezb.nl/&quot;&gt;http://ticons.fokkezb.nl/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://ionicframework.com/docs/cli/icon-splashscreen.html&quot;&gt;Ionic CLI&lt;/a&gt; has something similar that also supports PSD and AI files.&lt;/p&gt;
&lt;p&gt;Both can be used with a React Native environment.&lt;/p&gt;
&lt;h3&gt;Building&lt;/h3&gt;
&lt;p&gt;The React Native documentation covers the basics for releasing your app. I suggest two services that will help you deliver faster.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://microsoft.github.io/code-push/&quot;&gt;CodePush&lt;/a&gt; is a SAAS service (by Microsoft) with a CLI and a native module to include in your app. It will allow to bypass the store release process for minor updates. It works by saving your JS code and assets on the server, your app check if updates are available and download it in background. The next app restart will have the updated version.&lt;/p&gt;
&lt;p&gt;Another toolkit already used by many iOS and Android developers is &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://fastlane.tools/&quot;&gt;Fastlane&lt;/a&gt;. This is an automation tool that will handle many repeated tasks like certification and profile generation or creating screenshots for each device size. It also lives versioned in a config file just next to your app, this is the ultimate time saving tool for mobile development.&lt;/p&gt;
&lt;h3&gt;Continuous integration&lt;/h3&gt;
&lt;p&gt;After setting up the tests in my app, I was looking for a CI supporting both iOS and Android. I looked at &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt; which has a paid plan for OSX but instead I tried &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.bitrise.io/&quot;&gt;Bitrise&lt;/a&gt; which has also specific support for React Native and a free plan. After following the excellent tutorials from the Snowflake starter kit, I had a working build with jest tests, release bundle and release xcode build working! Below is the only file needed to make this work.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;format_version&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;1.1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;default_step_lib_source&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;https://github.com/bitrise-io/bitrise-steplib.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;  envs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;BITRISE_PROJECT_PATH&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;ios/example.xcodeproj&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    opts&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;      is_expand&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;BITRISE_SCHEME&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    opts&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;      is_expand&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;trigger_map&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;master&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;  is_pull_request_allowed&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;  workflow&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;primary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;workflows&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;  primary&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    steps&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;activate-ssh-key@3.1.1&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        title&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;Activate App SSH key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        inputs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;ssh_key_save_path&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;$HOME/.ssh/steplib_ssh_step_id_rsa&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;git-clone@3.3.3&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        inputs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;clone_depth&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;1&#039;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;change-workdir@1.0.1&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        inputs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;example-react-native-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;is_create_path&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;false&#039;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;script@1.1.2&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        title&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;npm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        inputs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;|-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-1&quot;&gt;            #!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-1&quot;&gt;            npm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;script@1.1.2&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        title&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;npm test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        inputs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;|-&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-1&quot;&gt;            #!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-1&quot;&gt;            npm test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;install-react-native@0.1.0&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;react-native-bundle@0.2.0&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        inputs&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;entry_file&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;./index.ios.js&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;An amazing ecosystem&lt;/h2&gt;
&lt;p&gt;Building our training program was really awesome with all the amazing resources and people experimenting with the library. Developing a React Native app is not only writing JS code but also having the right toolkit to iterate quickly and have a first class app at the end.&lt;/p&gt;
&lt;p&gt;If you want to know more and create an app from scratch during a three days session, head over to our &lt;a href=&quot;https://jolicampus.com/formations/react-native&quot;&gt;React Native training&lt;/a&gt;.&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/mon-premier-module-open-source-pour-react-native</id>
        <published>2016-08-11T11:00:00+02:00</published>
        <updated>2016-08-11T11:00:00+02:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/mon-premier-module-open-source-pour-react-native"/>
        <title>Mon premier module Open Source pour React Native</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="javascript" />            <category term="mobile" />            <category term="react" />            <category term="react-native" />        <summary><![CDATA[Souhaitant développer une application mobile pour une webradio avec comme cible Android et iOS, mon choix s&#039;est porté sur React Native qui fait beaucoup parler de lui ses derniers temps et que nous souhaitons…]]></summary>
        <content type="html">
            &lt;p&gt;Souhaitant développer une &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://play.google.com/store/apps/details?id=com.lacave&amp;amp;hl=fr&quot;&gt;application mobile pour une webradio&lt;/a&gt; avec comme cible Android et iOS, mon choix s&#039;est porté sur React Native qui fait beaucoup parler de lui ses derniers temps et que nous souhaitons utiliser à la place de Titanium.&lt;/p&gt;
&lt;p&gt;Ayant fait le tour des modules disponibles pour jouer un flux audio, je me suis aperçu qu&#039;il n&#039;y en avait aucun cross-platform. J&#039;ai donc décidé de créer mon propre module React Native. Cet article retrace ce parcours et les problèmes rencontrés lors du développement du module &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/tlenclos/react-native-audio-streaming&quot;&gt;react-native-audio-streaming&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ci-dessous un aperçu de la première version du module réalisé.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://raw.githubusercontent.com/tlenclos/react-native-audio-streaming/master/demo_ios.gif&quot; alt=&quot;Demo iOS&quot; /&gt;
&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://raw.githubusercontent.com/tlenclos/react-native-audio-streaming/master/demo_android.gif&quot; alt=&quot;Demo android&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Les recherches initiales&lt;/h2&gt;
&lt;p&gt;Le point de départ est bien souvent la question &amp;quot;Quelqu&#039;un l&#039;a-t-il déjà développé ?&amp;quot;. C&#039;est encore plus d&#039;actualité sur un environnement aussi dynamique que React Native où de nombreuses librairies sont créées chaque jour.&lt;/p&gt;
&lt;p&gt;Ce qui m&#039;amène sur l&#039;excellent dépôt de &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/jhabdas/lumpen-radio&quot;&gt;@jhabdas&lt;/a&gt; et ses &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://slides.com/jhabdas/streaming-audio-react-native/&quot;&gt;slides&lt;/a&gt; sur la création d&#039;une application iOS pour la webradio Lumpen.&lt;/p&gt;
&lt;h3&gt;iOS&lt;/h3&gt;
&lt;p&gt;La partie iOS du module est donc déjà bien avancée. L&#039;ensemble du code est sous licence MIT, je peux donc le récupérer. Il manque par contre la gestion des metadatas envoyés par le protocole &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://www.yoannsculo.fr/protocole-shoutcast-introduction-et-decorticage/&quot;&gt;Shoutcast&lt;/a&gt; (logiciel open source utilisé par de nombreuses webradio).&lt;/p&gt;
&lt;p&gt;Heureusement pour moi, une personne a déjà rajouté ce support &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/tumtumtum/StreamingKit/pull/179&quot;&gt;dans son fork&lt;/a&gt; et je peux donc le récupérer.&lt;/p&gt;
&lt;h3&gt;Android&lt;/h3&gt;
&lt;p&gt;Pour cette plateforme, le module &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/EstebanFuentealba/react-native-android-audio-streaming-aac&quot;&gt;react-native-android-audio-streaming-aac&lt;/a&gt; dispose déjà des fonctionnalités avec le support des métadonnées Shoutcast. Il utilise la librairie &lt;code&gt;aacDecoder&lt;/code&gt; qui ne semble plus maintenue mais l&#039;implémentation était déjà réalisée et j&#039;ai donc gardé cette librairie, une mise à jour la remplacera probablement par l&#039;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/google/ExoPlayer&quot;&gt;ExoPlayer&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Le module React Native&lt;/h2&gt;
&lt;h3&gt;Trouver un nom&lt;/h3&gt;
&lt;p&gt;Ce module va permettre de faire du streaming audio, tous les modules étant préfixés par &amp;quot;react-native&amp;quot;, je pars donc sur le nom &amp;quot;react-native-audio-streaming&amp;quot;. Après une rapide recherche sur npm, déception, le nom est déjà pris 😢 (pour information, ce module n&#039;existait pas encore lors de la réalisation de l&#039;application radio, qui bénéficiera de ce module plus tard). Peut être est-il possible de contribuer à ce module au lieu de créer le mien ?&lt;/p&gt;
&lt;p&gt;Le package npm ne possède pas de lien vers ses sources et aucune trace du dépôt dans ceux de l&#039;auteur. Je le contacte donc pour en savoir plus sur l&#039;état de son module.&lt;/p&gt;
&lt;p&gt;Le développeur, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/mmazzarolo&quot;&gt;Matteo Mazzarolo&lt;/a&gt; me répond qu&#039;il ne souhaite plus le maintenir et qu&#039;il a donc supprimé son module, tout en me proposant de transférer sa possession du package sur npm. Super !&lt;/p&gt;
&lt;h3&gt;Initialiser le projet&lt;/h3&gt;
&lt;p&gt;Ayant récupéré les différentes librairies et la possession du nom que je veux utiliser, il faut maintenant démarrer le développement du module.&lt;/p&gt;
&lt;p&gt;La première chose à faire est de choisir une licence, pour ce faire les sites &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://opensource.org/licenses&quot;&gt;opensource.org&lt;/a&gt; et &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://choosealicense.com/&quot;&gt;choosealicense.com&lt;/a&gt; permettent de se faire une idée rapidement. Je sélectionne donc la licence MIT qui possède le plus de liberté de partage du code.&lt;/p&gt;
&lt;p&gt;Pour le code, je souhaite avoir une application d&#039;exemple dans mon dépôt, après quelques recherches sur les bonnes manières d&#039;initialiser un module, je trouve la commande officielle &lt;code&gt;react-native new-library&lt;/code&gt; mais elle est peu documentée, ainsi qu&#039;un autre outil en cli : &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/frostney/react-native-create-library&quot;&gt;react-native-create-library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;La commande officielle nécessite un projet déjà créé et inclut une version ancienne de React Native. Je choisis donc la deuxième qui me crée les 3 projets de librairies associés (iOS, Android et même Windows !).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ react-native-create-library ReactNativeAudioStreaming
…
$ tree -d ./

├── android
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── reactlibrary

├── ios
│   └── RNReactNativeAudioStreaming.xcodeproj

└── windows
    └── RNReactNativeAudioStreaming
        └── RNReactNativeAudioStreaming
            └── Properties
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ensuite, j&#039;initialise le module et renseigne les informations de celui-ci :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Puis je créé l&#039;application d&#039;exemple et installe les dépendances :&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; Example&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span class=&quot;syntax-9&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; Example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;react-native&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt; ../&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La suite consiste à lier notre application d&#039;exemple avec notre package tout neuf, si l&#039;on suit la manière de développement des packages NPM, cela consiste à utiliser &lt;code&gt;npm link&lt;/code&gt; pour créer un lien symbolique vers notre module. Hélas, ils ne sont pas résolus par le packager de React Native (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/react-native/pull/9176&quot;&gt;problème bientôt résolu&lt;/a&gt;), et je dois donc copier coller mes changements pour les garder synchronisés avec la librairie… Une alternative créé par la communauté est l&#039;utilitaire &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/wix/wml&quot;&gt;wml&lt;/a&gt;, mais je ne l&#039;ai pas testé.&lt;/p&gt;
&lt;h3&gt;Développement et uniformisation des APIs&lt;/h3&gt;
&lt;p&gt;Étant donné que la majeure partie du module est native, nous ne pouvons pas bénéficier du live/hot reload proposé par le compilateur, il faut donc relancer l&#039;application à chaque modification via Xcode ou Android Studio. Toutefois, sur Android, nous pouvons profiter du build incrémental proposé par &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://gradle.org/blog/feature-spotlight-incremental-builds/&quot;&gt;Gradle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je ne vais pas détailler le code nécessaire pour exposer les fonctions ou envoyer des événements au runtime JS car cela est déjà bien détaillé dans la documentation officielle :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react-native/docs/native-modules-ios.html&quot;&gt;https://facebook.github.io/react-native/docs/native-modules-ios.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react-native/docs/native-modules-android.html&quot;&gt;https://facebook.github.io/react-native/docs/native-modules-android.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La principale difficulté est de savoir se débrouiller avec les trois langages, l&#039;Objective-C, le Java et le Javascript. Il vaut mieux s&#039;isoler au maximum dans un environnement que de s&#039;éparpiller à vouloir implémenter chaque fonctionnalité en parallèle.&lt;/p&gt;
&lt;p&gt;De plus, il faut garder en tête les limitations de chaque plateforme. Par exemple, sur iOS, nous disposons des événements &amp;quot;Remote control&amp;quot; et de l&#039;interface native lorsque l&#039;application est en background, par contre sur Android, nous devons implémenter cette interface à la main avec une notification active.&lt;/p&gt;
&lt;p&gt;Pour lier le code natif de notre module avec l&#039;application d&#039;exemple, nous devons les lier à la compilation avec la commande &lt;code&gt;react-native link react-native-audio-streaming&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Publication&lt;/h2&gt;
&lt;h3&gt;NPM&lt;/h3&gt;
&lt;p&gt;N&#039;ayant jamais publié de package sur NPM avant, j&#039;ai cherché le meilleur workflow disponible. La commande &lt;code&gt;npm publish&lt;/code&gt; est simple d&#039;utilisation mais il faut modifier la version à la main, créer la release et par conséquent il y a une forte probabilité d&#039;erreur.&lt;/p&gt;
&lt;p&gt;Le package &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/sindresorhus/np&quot;&gt;np&lt;/a&gt; propose un workflow plus complet qui vérifie l&#039;installation des dépendances, le code non commité, va lancer les tests et mettre à jour automatiquement la version dans le &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Open source&lt;/h3&gt;
&lt;p&gt;Tous les projets nécessitent un minimum d&#039;informations pour le démarrage ou l&#039;installation. Le README est la première chose qu&#039;un utilisateur va lire en arrivant sur votre librairie, il nécessite donc une attention particulière.&lt;/p&gt;
&lt;p&gt;Le plus important est d&#039;expliquer comment le module peut être installé et configuré. Pour React Native par exemple, cela revient à proposer la commande &lt;code&gt;npm install&lt;/code&gt; avec le nom du module, puis à ajouter les éléments à modifier pour lier le code natif du module à l&#039;application.&lt;/p&gt;
&lt;p&gt;Comme introduction, personnellement j&#039;apprécie une rapide liste des fonctionnalités de la librairie, avec, si nécessaire, plus de détails par la suite : notamment pour ce module, deux gifs montrant les différents comportement sur chaque plateforme (réalisé avec Giphy capture sur macOS).&lt;/p&gt;
&lt;p&gt;N&#039;hésitez pas à rajouter du code d&#039;exemple pour guider le développeur sur l&#039;utilisation de votre librairie. Dans mon cas, j&#039;ai copié/collé le code principal de l&#039;application d&#039;exemple qui inclut le composant de la librairie.&lt;/p&gt;
&lt;p&gt;L&#039;autre partie importante est le suivi des mises à jour via un CHANGELOG qui permet de suivre l&#039;évolution du projet mais surtout d&#039;informer lors de dépréciations d&#039;API. Je conseille fortement le site &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://keepachangelog.com&quot;&gt;keepachangelog.com&lt;/a&gt; pour plus d&#039;informations à ce sujet.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Je me suis aperçu que l&#039;open source est un travail de tous les jours, je n&#039;ai pour l&#039;instant qu&#039;un seul contributeur mais qui apporte sa vision et son code et il faut être prêt à en discuter et à prendre des décisions en commun. Je n&#039;ose imaginer le temps nécessaire pour maintenir et faire évoluer des projets très populaires…&lt;/p&gt;
&lt;p&gt;Excepté quelques ennuis pour gérer les dépendances natives, je trouve la création d&#039;un module natif agréable et plus facile qu&#039;avec Titanium (système de build plus complexe, SDK en global, peu de de documentations…). Les contributeurs sont aussi beaucoup plus nombreux avec plus de 2000 résultats sur snpm pour le mot clé &amp;quot;react-native&amp;quot; contre 1432 pour &amp;quot;titanium&amp;quot; (statistiques &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://gitt.io&quot;&gt;gitt.io&lt;/a&gt;) alors qu&#039;il est plus ancien.&lt;/p&gt;
&lt;p&gt;PS: Ce module a été utilisé dans l&#039;application &amp;quot;La Cave Webradio&amp;quot; disponible pour Android et iOS !&lt;/p&gt;
&lt;p&gt;&lt;a style=&quot;display: inline-block; background-image: url(&#039;https://play.google.com/intl/en_us/badges/images/generic/fr_badge_web_generic.png&#039;); height: 80px; width: 165px; background-size: contain; background-position: center center; background-repeat: no-repeat;&quot; rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://play.google.com/store/apps/details?id=com.lacave&amp;amp;hl=fr&amp;amp;utm_source=global_co&amp;amp;utm_medium=prtnr&amp;amp;utm_content=Mar2515&amp;amp;utm_campaign=PartBadge&amp;amp;pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1&quot;&gt;&lt;/a&gt;&lt;a style=&quot;display:inline-block;overflow:hidden;background:url(https://linkmaker.itunes.apple.com/images/badges/en-us/badge_appstore-lrg.svg) no-repeat;width: 165px;height: 80px;background-position: center center;&quot; rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://itunes.apple.com/fr/app/la-cave-webradio/id1141990341?mt=8&quot;&gt;&lt;/a&gt;&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/retour-sur-react-europe-la-conference-hype-du-moment</id>
        <published>2016-06-15T16:15:00+02:00</published>
        <updated>2016-06-15T16:15:00+02:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/retour-sur-react-europe-la-conference-hype-du-moment"/>
        <title>Retour sur React Europe, la conférence hype du moment</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="conférence" />            <category term="react" />            <category term="reactnative" />            <category term="graphql" />            <category term="redux" />            <category term="flow" />        <summary><![CDATA[Nouveauté pour JoliCode, nous étions cette année sponsor et participants à la conférence ReactEurope qui s&#039;est déroulée à Paris les 2 et 3 juin à l&#039;espace Charenton. Pourquoi ?
Nous aimons PHP mais faisons,…]]></summary>
        <content type="html">
            &lt;p&gt;Nouveauté pour JoliCode, nous étions cette année sponsor et participants à la conférence ReactEurope qui s&#039;est déroulée à Paris les 2 et 3 juin à l&#039;espace Charenton. Pourquoi ?&lt;/p&gt;
&lt;p&gt;Nous aimons PHP mais faisons, au fil de nos projets, de plus en plus de JavaScript. Nous utilisons déjà la librairie React sur de nombreux projets et cette conférence nous a paru incontournable. C’était l&#039;occasion d&#039;en apprendre les subtilités et d’entrevoir son avenir, auprès des meilleurs.&lt;/p&gt;
&lt;p&gt;Mais React, plus qu’une librairie, c’est un écosystème. La conférence couvre donc aussi bien React Native que le paradigme &amp;quot;unidirectional data flow&amp;quot; implémenté par Redux, ou d’autres réalisations pour faciliter l’expérience de développement.&lt;/p&gt;
&lt;p&gt;Les conférences techniques de cette édition gravitaient pour la plupart autour de trois thèmes principaux : React en profondeur, React Native, GraphQL.&lt;/p&gt;
&lt;h2&gt;React&lt;/h2&gt;
&lt;p&gt;Dan Abramov a lancé les hostilités en venant célébrer avec nous la première bougie de Redux dont il est à l&#039;origine. Tel un Super Saïyen niveau 5, Redux a démonté les autres implémentations de Flux par son taux d&#039;adoption par la communauté.&lt;/p&gt;
&lt;p&gt;La conférence suivante, présentée par &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/linClark&quot;&gt;Lin Clark&lt;/a&gt;, développeuse chez Mozilla, qui travaille sur un nouveau navigateur utilisant React et Redux, est notre coup de coeur de ces deux journées.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/react-europe/React_Europe_2016-Lin_Clark.e3cc0221.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2016/react-europe/React_Europe_2016-Lin_Clark.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 861px; ; aspect-ratio: calc(861 / 422)&quot; src=&quot;https://jolicode.com//media/cache/content/2016/react-europe/React_Europe_2016-Lin_Clark.png&quot; alt=&quot;Lin Clark&quot; title=&quot;Lin Clark&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Durant ce talk illustré par d&#039;adorables cartoons faits maison, Lin nous a pris par la main pour nous emmener dans les profondeurs du fonctionnement interne de React, afin d&#039;aboutir tout naturellement à quelques techniques simples pour améliorer les performances de nos applications. On retiendra entre autres ces quelques conseils :&lt;/p&gt;
&lt;p&gt;&lt;picture class=&quot;js-dialog-target&quot; data-original-url=&quot;/media/original/2016/react-europe/React_Europe-Lin_Clark-tips.JPG&quot; data-original-width=&quot;2307&quot; data-original-height=&quot;1626&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/react-europe/React_Europe-Lin_Clark-tips.478de49e.webp&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/media/cache/content/2016/react-europe/React_Europe-Lin_Clark-tips.JPG&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 996px; ; aspect-ratio: calc(2307 / 1626)&quot; src=&quot;https://jolicode.com//media/cache/content/2016/react-europe/React_Europe-Lin_Clark-tips.JPG&quot; alt=&quot;Lin Clark tips&quot; title=&quot;Lin Clark tips&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;utiliser la méthode &lt;code&gt;shouldComponentUpdate&lt;/code&gt; dès que cela peut entraîner un gain de performances. On évite ainsi de re-render les composants inutilement à chaque infime changement du state ;&lt;/li&gt;
&lt;li&gt;renseigner systématiquement la props &lt;code&gt;key&lt;/code&gt; des composants rendus dans des boucles (vous savez, ce fameux warning qu&#039;on ignore gentiment la plupart du temps). React utilise ces clés pour déterminer la position des éléments enfants et déterminer s&#039;il doit effectivement les re-render ou simplement échanger leurs positions dans la liste par exemple ;&lt;/li&gt;
&lt;li&gt;utiliser au maximum l&#039;immutabilité, pour limiter le &lt;code&gt;shouldComponentUpdate&lt;/code&gt; à une simple comparaison de références ;&lt;/li&gt;
&lt;li&gt;définir le &lt;code&gt;state&lt;/code&gt; des composants au plus bas niveau possible. Par exemple, un composant List devrait recevoir en &lt;code&gt;props&lt;/code&gt; uniquement les id des items qu&#039;il contient, et laisser la responsabilité de l&#039;objet aux composants ListItem. De cette manière, si l&#039;on modifie un des items, seul le composant enfant dont l&#039;objet a changé sera re-rendered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Max Stoiber &amp;amp; Nik Graf nous ont fait la présentation de leur outil &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/carteb/carte-blanche&quot;&gt;carte blanche&lt;/a&gt;, qui permet de tester le rendu des composants dans toutes leurs variations possibles. On peut ainsi changer à la volée les &lt;code&gt;props&lt;/code&gt; et le &lt;code&gt;state&lt;/code&gt; des composants, grâce au hot loader intégré, ce qui permet de détecter simplement les edge cases et les problèmes de design éventuels. Ce type d’outil va certainement s’avérer très pratique pour les développeurs mais aussi pour les recettes.&lt;/p&gt;
&lt;p&gt;Les autres conférences nous ont présenté &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/acdlite/recompose&quot;&gt;Recompose&lt;/a&gt;, le fonctionnement interne de &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/flow&quot;&gt;Flow&lt;/a&gt; ou encore la librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://formidable.com/open-source/victory&quot;&gt;Victory&lt;/a&gt; qui regroupe des composants de visualisation de données.&lt;/p&gt;
&lt;h2&gt;React Native&lt;/h2&gt;
&lt;p&gt;On ne présente plus React, mais certains d&#039;entre vous n&#039;ont peut-être pas encore eu l&#039;occasion de se plonger dans l&#039;univers de &lt;a href=&quot;https://jolicode.com//blog/crossing-the-native-bridge-to-build-apps-with-javascript&quot;&gt;React Native&lt;/a&gt;. La techno était au coeur de nombreuses conférences, abordant principalement deux de ses aspects les plus délicats : les animations et la navigation.&lt;/p&gt;
&lt;p&gt;Si React Native vous est inconnu, regardez la conférence de Bonnie Eiseman qui raconte l’histoire et l’évolution de React Native depuis sa première bêta. Elle revient sur les problèmes rencontrés par les early adopters (pas de support pour Android, API incomplète…). Elle décrit ainsi l&#039;évolution très rapide de React Native et l’engouement massif qui a suivi la première release. Depuis, React Native supporte Android et le support de Windows Universal Apps a été annoncé lors de la conférence F8.&lt;/p&gt;
&lt;h3&gt;Improve React Native animations&lt;/h3&gt;
&lt;p&gt;Les animations natives présentent un certain nombre de limitations. En effet, même si elles permettent des performances optimales et un comportement spécifique aux plateformes à moindre coût, il n’existe qu’un nombre limité de composants disponibles, qu’il est de plus impossible de customiser. &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/kzzzf&quot;&gt;Krzysztof Magiera&lt;/a&gt; tente de répondre à ces problématiques via l’utilisation de la librairie &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/react-native/tree/0.27-stable/Libraries/Animated&quot;&gt;Animated&lt;/a&gt;, intégrée à React Native. Celle-ci apporte la flexibilité qui manque aux animations natives et permet de définir des animations gestuelles avec des performances supérieures, à la condition toutefois de ne pas s’attaquer aux animations de layout. Pour ces dernières, il faudra utiliser des API complémentaires.&lt;/p&gt;
&lt;h3&gt;Navigation // Eric Vicenti&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://twitter.com/EricVicenti&quot;&gt;Eric&lt;/a&gt; nous a fait une démonstration du composant de navigation cross-platform (iOS, Android, Windows, NodeJS et les navigateurs) de React Native.
Ce composant est encore expérimental mais déjà &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/react-native/tree/master/Libraries/NavigationExperimental&quot;&gt;disponible&lt;/a&gt;. Il est d’ores et déjà utilisé en production.&lt;/p&gt;
&lt;h2&gt;GraphQL et Falcor, donner le pouvoir au client&lt;/h2&gt;
&lt;p&gt;Créé pour les besoins de Facebook et utilisé depuis 4 ans, GraphQL se veut être une alternative aux APIs (REST) afin de permettre aux clients d&#039;accéder aux données en décrivant le format de réponse attendu. Le principe : décrire explicitement toutes les données dont ont besoin nos composants. Le tout est ensuite récupéré en une seule requête afin d’hydrater ces composants.&lt;/p&gt;
&lt;p&gt;Exemple de requête GraphQL pour récupérer le nom des utilisateurs :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  user {
    name
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dans la conférence sur le futur de GraphQL, présentée par Laney Kuenzel
et Lee Byron, nous avons particulièrement apprécié la proposition expérimentale des annotations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@defer&lt;/code&gt;, qui permet d’éviter de récupérer toutes les données d’un coup (ex: on affiche l’article, ensuite on affiche les commentaires) mais de différer la récupération des données secondaires ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@live&lt;/code&gt;, sans doute la plus bluffante, qui permettrait de visualiser la donnée en temps réel ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@stream&lt;/code&gt;, comme son nom l’indique, cette annotation permet de créer un flux, pour éviter un temps d’attente trop important pour visualiser une liste.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/react-europe/React_Europe-GraphQL_Annotations.d229e3cf.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2016/react-europe/React_Europe-GraphQL_Annotations.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 765px; ; aspect-ratio: calc(765 / 405)&quot; src=&quot;https://jolicode.com//media/cache/content/2016/react-europe/React_Europe-GraphQL_Annotations.png&quot; alt=&quot;GraphQL annotations&quot; title=&quot;GraphQL annotations&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Les speakers nous ont détaillé comment le problème des données en temps réel était actuellement résolu sur Facebook, en utilisant les subscriptions GraphQL, une implémentation du pattern publisher/subscriber. Le principe est de faire une requête GraphQL indiquant l’action que l’on écoute, comme la liste des commentaires de notre publication récente. Puis, à chaque fois qu’un nouveau commentaire sera publié, notre client recevra ce nouveau commentaire.&lt;/p&gt;
&lt;p&gt;En tout cas, si on pouvait être sceptique lors des premières annonces de GraphQL, les évolutions qu’on entrevoit dans son futur laissent présager de la résolution de problèmes communs à toutes les implémentations de clients et auxquels il n’existe pas actuellement de solution unique.&lt;/p&gt;
&lt;p&gt;Jafar Husain de Netflix nous a présenté leur alternative à GraphQL : &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/Netflix/falcor&quot;&gt;Falcor&lt;/a&gt;. Leur modèle de données étant relativement simple (moins d’une vingtaine d’entités), GraphQL était long à mettre en place et ne correspondait pas réellement à leurs besoins. Ils ont donc développé une alternative, Falcor, qui répond au même problème initial que GraphQL mais dont la mise en place sur un projet existant est plus rapide et qui est mieux adapté, selon eux, à un modèle de données plus léger.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2016/react-europe/React_Europe-Falcor.e000352f.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2016/react-europe/React_Europe-Falcor.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 856px; ; aspect-ratio: calc(856 / 434)&quot; src=&quot;https://jolicode.com//media/cache/content/2016/react-europe/React_Europe-Falcor.png&quot; alt=&quot;Falcor vs GraphQL&quot; title=&quot;Falcor vs GraphQL&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Malgré les 800 développeurs présents dans la salle, nous avons également pu assister à des conférences moins techniques :&lt;/p&gt;
&lt;h2&gt;Being successful at open source&lt;/h2&gt;
&lt;p&gt;Dans cette conférence qui détonait par son aspect bien moins technique, &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://twitter.com/@vjeux&quot;&gt;Christophe Cheadeau&lt;/a&gt;, qui a travaillé à l&#039;open sourcisation (oui oui) de React, React Native, Jest, et d&#039;autres projets Facebook, nous a offert un retour d&#039;expérience édifiant. Des points évoqués par Christophe, il ressort que la communication est la clé de voûte de ces réussites, de la propagation de l&#039;information via les réseaux sociaux, les articles de blog, jusqu&#039;à la création de tickets Github pour interroger la communauté sur les points faibles des libs et sur leurs réalisations. On en retient que le succès fulgurant de ces librairies n&#039;est pas seulement dû au grand nom qui les porte, ni même peut-être aux librairies elles-mêmes, mais bien à un travail réfléchi et de chaque instant, et qu&#039;il est aussi à notre portée !&lt;/p&gt;
&lt;h2&gt;On the spectrum of abstraction&lt;/h2&gt;
&lt;p&gt;Cheng Lou nous plonge dans les profondeurs de l&#039;abstraction, et de tout ce que cette grande notion implique dans notre travail de tous les jours. Observer les lignes de code avec plus de recul permet de se rendre compte de la nécessité de travailler parfois à un niveau plus bas, plus concret, et en se concentrant d&#039;abord sur les use-cases qui nous intéressent vraiment, plutôt que d&#039;essayer de répondre à tous les cas possibles via des implémentations plus abstraites. Un talk rafraîchissant qui pose un regard nouveau, critique et réfléchi sur notre frénésie des frameworks.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;React Europe est LA conférence pour rencontrer les rock stars de l&#039;univers React. Une grande partie des conférenciers sont employés chez Facebook ; l’entreprise est à la fois moteur et travaille à la stabilité de React et des technologies liées en s’associant aux contributeurs principaux de l’écosystème.
La conférence étant internationale, nous avons pu échanger avec des développeurs norvégiens, italiens, américains, polonais… Une particularité suffisamment rare dans les conférences parisiennes pour mériter d’être soulignée.
Merci à l&#039;organisation et aux speakers pour ce bel événement, dont vous pouvez retrouver toutes les conférences sur la &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A&quot;&gt;chaîne Youtube de React Europe&lt;/a&gt;.&lt;/p&gt;

        </content>
    </entry>    <entry>
        <id>https://jolicode.com/blog/crossing-the-native-bridge-to-build-apps-with-javascript</id>
        <published>2015-10-01T18:00:00+02:00</published>
        <updated>2015-10-01T18:00:00+02:00</updated>
        <link type="text/html" rel="alternate" href="https://jolicode.com/blog/crossing-the-native-bridge-to-build-apps-with-javascript"/>
        <title>Crossing the native bridge to build apps with Javascript</title>
        <author>
            <name>JoliCode Team</name>
            <uri>https://jolicode.com/</uri>
        </author>            <category term="titanium" />            <category term="react" />            <category term="nativescript" />            <category term="reactnative" />        <summary><![CDATA[We are building cross-platform apps with Titanium since it came out in 2009, it was a great journey and we contributed to the platform, the builder and also created some widgets.
For now, we found no…]]></summary>
        <content type="html">
            &lt;p&gt;We are building cross-platform apps with Titanium since it came out in 2009, it was a great journey and &lt;a href=&quot;https://jolicode.com//blog/tag/titanium&quot;&gt;we contributed to the platform, the builder and also created some widgets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For now, we found no real free and open-source competitors to Titanium (sorry &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://xamarin.com/&quot;&gt;@xamarin&lt;/a&gt;), but there are new players in town, so let&#039;s see what they have to offer !&lt;/p&gt;
&lt;p&gt;Hello &lt;strong&gt;NativeScript&lt;/strong&gt; and &lt;strong&gt;React Native&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Why these two new libraries are coming out in 2015?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, the javascript ecosystem is evolving and we all know it (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://xn--h4hg.ws/2015/07/27/too-many-tools/&quot;&gt;maybe too much&lt;/a&gt;). It is so popular that we try to build everything with it (website, server, IoT…) and mobile apps too ! Developers are looking for ways to share &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/google/j2objc&quot;&gt;code across platforms&lt;/a&gt; or even between &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://isomorphic.net/&quot;&gt;client and server&lt;/a&gt;, but it’s better if we can do it by using the same language and the same code !&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Again, new tools? Seriously?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I know I know… but apart from Titanium, there was no competitors for building native apps with javascript and competition is always good, we will see what they come up to appeal the developers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What is the challenge?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nearly the same as building a mobile web app. &lt;strong&gt;Performance&lt;/strong&gt; and &lt;strong&gt;UI&lt;/strong&gt;. The rest is for the developer comfort.&lt;/p&gt;
&lt;h2&gt;Frameworks&lt;/h2&gt;
&lt;p&gt;Those three frameworks are SDK to build native apps for iOS, Android and Windows (only Titanium for now). They expose native api through the bridge that you can call via javascript. Your code is then interpreted at runtime via JSCore on iOS and V8 runtime on Android.&lt;/p&gt;
&lt;h3&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/appcelerator/titanium_mobile&quot;&gt;Titanium&lt;/a&gt;&lt;/h3&gt;
&lt;iframe src=&quot;https://ghbtns.com/github-btn.html?user=appcelerator&amp;amp;repo=titanium_mobile&amp;amp;type=star&amp;amp;count=true&amp;amp;size=large&quot; frameborder=&quot;0&quot; scrolling=&quot;0&quot; width=&quot;160px&quot; height=&quot;30px&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2015/09/titanium-logo.06e36b18.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2015/09/titanium-logo.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 250px; ; aspect-ratio: calc(250 / 250); float:right; margin:0 0 10px 10px;&quot; src=&quot;https://jolicode.com//media/cache/content/2015/09/titanium-logo.png&quot; alt=&quot;Titanium&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platforms&lt;/strong&gt;: iOS, Android, Windows phone (beta)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Company&lt;/strong&gt;: Appcelerator&lt;/p&gt;
&lt;p&gt;Titanium is the oldest framework of this post, since july 2015, it partially &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://www.appcelerator.com/blog/2015/07/4-1-0-ga-now-available/&quot;&gt;supports windows&lt;/a&gt;. The SDK is written in Objective-C, Java and C++ and exposes it via classes called Proxies. A proxy is a native classe exposing properties and methods to the javascript context.&lt;/p&gt;
&lt;p&gt;It is actively maintained by Appcelerator, it is mature, has an IDE and a MVC framework called &lt;em&gt;Alloy&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We built many apps with it and wrote some &lt;a href=&quot;https://jolicode.com//blog/tag/titanium&quot;&gt;blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/NativeScript/NativeScript&quot;&gt;NativeScript&lt;/a&gt;&lt;/h3&gt;
&lt;iframe src=&quot;https://ghbtns.com/github-btn.html?user=NativeScript&amp;amp;repo=NativeScript&amp;amp;type=star&amp;amp;count=true&amp;amp;size=large&quot; frameborder=&quot;0&quot; scrolling=&quot;0&quot; width=&quot;160px&quot; height=&quot;30px&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2015/09/nativescript-logo.e6a46b31.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2015/09/nativescript-logo.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 250px; ; aspect-ratio: calc(250 / 250); float:right; margin:0 0 10px 10px;&quot; src=&quot;https://jolicode.com//media/cache/content/2015/09/nativescript-logo.png&quot; alt=&quot;Native script&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platforms&lt;/strong&gt;: iOS, Android&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Company&lt;/strong&gt;: Telerik&lt;/p&gt;
&lt;p&gt;Out since march 2015, NativeScript is an open source SDK and runtime. Build by Telerik, some paid solutions includes a web IDE or other service integration. SDK is written in javascript and the runtime is native.&lt;/p&gt;
&lt;p&gt;Wait, what? SDK in Javascript? What kind of black magic is…&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; enums &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; require&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;ui/enums&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; locationModule &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; require&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;location&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; common &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; require&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;location/location-common&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;global.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;moduleMerge&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(common, &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;LocationListenerImpl&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; extends&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-7&quot;&gt;NSObject&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-7&quot;&gt;CLLocationManagerDelegate&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    public&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; static&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; ObjCProtocols &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; [CLLocationManagerDelegate];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    static&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; new&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;LocationListenerImpl&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;        return&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt; super&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    private&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; _onLocation&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;locationModule&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt; any&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    private&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; _onError&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-6&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt; any&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh okay, this is just some Typescript class extending an Objective-C class.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2015/09/pappers.06d99537.webp&quot; /&gt;&lt;source type=&quot;image/gif&quot; srcset=&quot;/media/cache/content/2015/09/pappers.gif&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 350px; ; aspect-ratio: calc(350 / 225)&quot; src=&quot;https://jolicode.com//media/cache/content/2015/09/pappers.gif&quot; alt=&quot;Pappers are flying&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We saw in the previous code sample that a common module was imported and merged with the exports, this is the official API exposed by the SDK and available for both platforms.&lt;/p&gt;
&lt;p&gt;Metadatas for all native APIs are generated when building the app and it allows to call native functions from JS files.&lt;/p&gt;
&lt;h3&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/react-native/&quot;&gt;React Native&lt;/a&gt;&lt;/h3&gt;
&lt;iframe src=&quot;https://ghbtns.com/github-btn.html?user=facebook&amp;amp;repo=react-native&amp;amp;type=star&amp;amp;count=true&amp;amp;size=large&quot; frameborder=&quot;0&quot; scrolling=&quot;0&quot; width=&quot;160px&quot; height=&quot;30px&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2015/09/react-native-logo.7c9c6c5f.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2015/09/react-native-logo.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 250px; ; aspect-ratio: calc(250 / 250); float:right; margin:0 0 10px 10px;&quot; src=&quot;https://jolicode.com//media/cache/content/2015/09/react-native-logo.png&quot; alt=&quot;React Native logo&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platforms&lt;/strong&gt;: iOS, Android&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Company&lt;/strong&gt;: Facebook&lt;/p&gt;
&lt;p&gt;Also released open source in march 2015 (and buzzing since). Based on the javascript library of the same name, React Native allows to develop iOS and Android mobile apps with the power of components.&lt;/p&gt;
&lt;p&gt;Facebook posted twice on their blog, once for the &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/&quot;&gt;iOS release (mars)&lt;/a&gt; and once for the &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://code.facebook.com/posts/1189117404435352/react-native-for-android-how-we-built-the-first-cross-platform-react-native-app&quot;&gt;Android release (september)&lt;/a&gt;. I recommend these posts, it helps understanding the history and progression of the library.&lt;/p&gt;
&lt;h2&gt;Development architecture&lt;/h2&gt;
&lt;h3&gt;MVC&lt;/h3&gt;
&lt;p&gt;With Titanium, we can use a framework on top of the SDK called &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/appcelerator/alloy&quot;&gt;Alloy&lt;/a&gt;. Generally speaking, it provides three paradigms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Models&lt;/strong&gt; provide the business logic, containing the rules, data and state of the application;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Views&lt;/strong&gt; provide the GUI components to the user, either presenting data or allowing the user to interact with the model data;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controllers&lt;/strong&gt; provide the glue between the model and view components in the form of application logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Behind the scene, it uses &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://backbonejs.org/#Model&quot;&gt;Backbone&lt;/a&gt; for the models, views are built in XML from Titanium UI components and controllers are extending Backbone.Events. They also expose view components with an id in the var &lt;code&gt;$&lt;/code&gt;. For example if you want to update a label with the id &amp;quot;title&amp;quot; you can write in your controller:&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;$.title.text &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; ‘My title’;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Controllers are just modules and can be exported and created from other controllers, which is great to split your app into reusable components.&lt;/p&gt;
&lt;p&gt;NativeScript uses nearly the same architecture but with raw models, although they use quite a lot of the observable pattern in the examples.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; observableArrayModule &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt; require&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;data/observable-array&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt; new&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; observableArrayModule.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;ObservableArray&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	{ name : &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;Name 1&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	{ name : &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;Name 2&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;React + Flux&lt;/h3&gt;
&lt;p&gt;React does not force any architecture as it is just a view library with components. I think that &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://facebook.github.io/flux/&quot;&gt;Flux&lt;/a&gt; is the way to go (see comparison of other flux-based library). The unidirectional data flow is great for the declarative programming approach used in React (because we only declare views with it’s own data).&lt;/p&gt;
&lt;p&gt;More recently, Facebook introduced Relay and GraphQL, which seems nice but force to have a GraphQL server side implementation. I prefer the approach of &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/RickWong/react-transmit&quot;&gt;React Transmit&lt;/a&gt; with promises. Both these libraries remove the gap between the component and its data by including the query.&lt;/p&gt;
&lt;p&gt;Here is a sample code of a list view populated with data from a json webservice.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-5&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; AwesomeProject &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; React.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;createClass&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  getInitialState&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      dataSource: &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; ListView.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;DataSource&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;        rowHasChanged&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;row1&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;row2&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; row1 &lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;!==&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; row2,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      loaded: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  componentDidMount&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-11&quot;&gt;    this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  fetchData&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;    fetch&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(REQUEST_URL)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      .&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; response.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      .&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;syntax-12&quot;&gt;responseData&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;=&gt;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-11&quot;&gt;        this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;          dataSource: &lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.state.dataSource.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;cloneWithRows&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;(responseData.movies),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;          loaded: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      .&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;  render&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    if&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.state.loaded) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;      return&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt; this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;renderLoadingView&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;    return&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span class=&quot;syntax-5&quot;&gt;ListView&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;        dataSource&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.state.dataSource&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;        renderRow&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;syntax-11&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;.renderRow&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-8&quot;&gt;        style&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;styles.listView&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;      /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-4&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Dev tools and debug&lt;/h2&gt;
&lt;h3&gt;IDE&lt;/h3&gt;
&lt;p&gt;Titanium has an official IDE called &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://www.appcelerator.com/platform/appcelerator-studio/&quot;&gt;Appcelerator Studio&lt;/a&gt; integrated with many Appcelerator services such as Cloud Services (database as a service).&lt;/p&gt;
&lt;p&gt;For all the frameworks you can use the IDE or text editor of your choice since they always provide CLI tools to build the app.&lt;/p&gt;
&lt;h3&gt;Live reload&lt;/h3&gt;
&lt;p&gt;Titanium has an official live reload implementation called LiveView, there is also a community one called TiShadow that &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://jolicode.github.io/automating-workflow-ticonf2014-talk/&quot;&gt;we use quite a lot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The NativeScript one is called LiveSync, unfortunately these tools are not really just reloading the code but restarting the app after syncing it. The React one is more efficient and transparent, we can also force the reload with &lt;code&gt;cmd+R&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Debug&lt;/h3&gt;
&lt;p&gt;The three frameworks have at least runtime logs and &lt;code&gt;console.log&lt;/code&gt; to debug variables.&lt;/p&gt;
&lt;p&gt;Appcelerator Studio has a nice debug mode and handles breakpoints.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;http://docs.appcelerator.com/platform/latest/images/download/attachments/29004940/DebugPerspective.png&quot; alt=&quot;Appcelerator Studio debug&quot; /&gt;&lt;/p&gt;
&lt;p&gt;NativeScript and ReactNative use the &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://developer.chrome.com/devtools/docs/javascript-debugging&quot;&gt;chrome debug tools&lt;/a&gt; with remote debugging.&lt;/p&gt;
&lt;p&gt;The implementation is more advanced for React as you can debug components individually with the help of React Developer tools or use the built-in UI inspector in the simulator.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2015/09/debug-react-native-alert-350.683f20b6.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2015/09/debug-react-native-alert-350.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 350px; ; aspect-ratio: calc(350 / 448)&quot; src=&quot;https://jolicode.com//media/cache/content/2015/09/debug-react-native-alert-350.png&quot; alt=&quot;React native debug menu&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/media/cache/content-webp/2015/09/react-native-inspector-350.0c2adbee.webp&quot; /&gt;&lt;source type=&quot;image/png&quot; srcset=&quot;/media/cache/content/2015/09/react-native-inspector-350.png&quot; /&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width: 350px; ; aspect-ratio: calc(350 / 374)&quot; src=&quot;https://jolicode.com//media/cache/content/2015/09/react-native-inspector-350.png&quot; alt=&quot;React native inspector&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2&gt;Styling&lt;/h2&gt;
&lt;p&gt;Titanium uses TSS (Titanium Style Sheet) which are file with a json like syntax. The property available are the properties of Titanium Object, for example if the view is a Button (Ti.UI.Button) with id &lt;code&gt;login&lt;/code&gt;, you can set the styles like this:&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;#login&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  backgroundColor: red;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  width: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  height: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  title: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&quot;Login&quot;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NativeScript try to be closer to CSS and handle a &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/NativeScript/docs/blob/master/styling.md#supported-properties&quot;&gt;subset&lt;/a&gt; of rules that are next applied to the native object. A fancy feature is that we can import external files from a server.&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;Button {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;width: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;style: solid;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;color: #&lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;034793&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;radius: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;TextField {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	background&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;color: #FAFAFA;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;width: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;style: solid;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;color: #C7C7CC;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;	border&lt;/span&gt;&lt;span class=&quot;syntax-4&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;radius: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same for React but implemented in plain javascript object (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/facebook/css-layout&quot;&gt;see the open source project css-layout&lt;/a&gt;). They choose to implement Flexbox for the layout, which is the future of layout in CSS. I struggled a bit with it but in the end it seems more powerful, and for @vdesdoigts our main designer, it was as easy as in CSS (&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Using_CSS_flexible_boxes&quot;&gt;see the doc on MDN&lt;/a&gt;).&lt;/p&gt;
&lt;pre class=&quot;syntax-0&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;StyleSheet.&lt;/span&gt;&lt;span class=&quot;syntax-8&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  container: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    flex: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    justifyContent: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;center&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    alignItems: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;center&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    backgroundColor: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;#F5FCFF&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  welcome: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    fontSize: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    textAlign: &lt;/span&gt;&lt;span class=&quot;syntax-1&quot;&gt;&#039;center&#039;&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;    margin: &lt;/span&gt;&lt;span class=&quot;syntax-3&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;syntax-2&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;syntax-2&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Write/learn once, deploy anywhere is valuable to a lot of people, it is valuable for us. There is no best solution and there is always tradeoffs, you have to find the one that fit the best to your needs.
If you prefer stability, Titanium is the way to go, it is the first in place and has some &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://www.appcelerator.com/product/&quot;&gt;great enterprise feature&lt;/a&gt;. If you value most the UI, React Native has already some &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://react.parts/native-ios&quot;&gt;awesome contributions&lt;/a&gt; since it’s mainly a view library adopted by developers and front end designers, it also has the biggest community right now. NativeScript is a nice alternative since Telerik is known to offer &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://www.telerik.com/support/demos&quot;&gt;some great UI &lt;/a&gt;(but not for free), and if you plan to access a lot the bridge and connects to… native script :p.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Titanium
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://www.tidev.io/&quot;&gt;http://www.tidev.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://gitt.io/&quot;&gt;http://gitt.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NativeScript
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://www.nativescript.org/blog&quot;&gt;https://www.nativescript.org/blog&lt;/a&gt;
I did not find any content from the community... ¯\&lt;em&gt;(ツ)&lt;/em&gt;/¯&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ReactNative
&lt;ul&gt;
&lt;li&gt;Impressions and app
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://jlongster.com/First-Impressions-using-React-Native&quot;&gt;http://jlongster.com/First-Impressions-using-React-Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://herman.asia/building-a-flashcard-app-with-react-native&quot;&gt;http://herman.asia/building-a-flashcard-app-with-react-native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://github.com/iSimar/HackerNews-React-Native&quot;&gt;https://github.com/iSimar/HackerNews-React-Native&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Playground &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;https://rnplay.org/&quot;&gt;https://rnplay.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Components &lt;a rel=&quot;nofollow noopener noreferrer&quot; href=&quot;http://react.parts/native&quot;&gt;http://react.parts/native&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

        </content>
    </entry></feed>
