<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arnaud Ambroselli</title>
    <description>The latest articles on DEV Community by Arnaud Ambroselli (@arnaudambro).</description>
    <link>https://dev.to/arnaudambro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F36046%2Fcb1f3a24-c4c2-4a74-957c-2caa282f7228.jpeg</url>
      <title>DEV Community: Arnaud Ambroselli</title>
      <link>https://dev.to/arnaudambro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arnaudambro"/>
    <language>en</language>
    <item>
      <title>Setup the easiest i18n system with NO KEYS</title>
      <dc:creator>Arnaud Ambroselli</dc:creator>
      <pubDate>Sat, 17 May 2025 15:39:26 +0000</pubDate>
      <link>https://dev.to/arnaudambro/setup-the-easiest-i18n-system-with-no-keys-40kc</link>
      <guid>https://dev.to/arnaudambro/setup-the-easiest-i18n-system-with-no-keys-40kc</guid>
      <description>&lt;p&gt;Alright, let's cut to the chase. You're building a React MVP. You need to be fast, lean, and focused on validating your core idea. So why, oh why, are you already thinking about &lt;code&gt;t('user.welcome.message.short')&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Internationalization (i18n) is crucial for global reach, no doubt. But for an MVP, traditional i18n setup is often a premature optimisation, a time sink when you should be shipping and iterating. It means wrestling with JSON files, getting lost with keys everywhere in your app, and losing velocity at a time you shouldn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embrace the "Keyless" Freedom with &lt;code&gt;i18n-keyless&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is where the "keyless" philosophy, then first time embodied by &lt;a href="https://github.com/arnaudambro/i18n-keyless" rel="noopener noreferrer"&gt;&lt;code&gt;i18n-keyless&lt;/code&gt;&lt;/a&gt;, becomes your MVP's best friend.&lt;/p&gt;

&lt;p&gt;The concept is refreshingly simple: &lt;strong&gt;Just write your UI text directly in your components, in your main language. That's it.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;I18nKeyless&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i18n-keyless-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// any language supported&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HeroSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;The Next Big Thing is Here!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Seriously, it's awesome. Sign up now.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Let's Go!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;I18nKeyless&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You build, you write, you iterate.&lt;br&gt;
No key invention, no initial translation file juggling.&lt;/p&gt;

&lt;p&gt;Try it here below within Stackblitz&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/vitejs-vite-ttaib9fx?file=index.html" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This is a Game-Changer for MVPs:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Blazing Speed:&lt;/strong&gt; You're not bogged down by i18n ceremony. Code flows faster. No velocity loss.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Laser Focus:&lt;/strong&gt; Concentrate 100% on core features and user experience.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cleaner Code:&lt;/strong&gt; Your JSX is just straightforward text. Much easier to read and modify during rapid prototyping.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Painless Text Changes:&lt;/strong&gt; Need to tweak that heading? Just change it. No key lookups or file updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a tool like &lt;code&gt;i18n-keyless&lt;/code&gt; is about getting i18n out of your mental load. For ever.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, How Does This Sorcery Work?
&lt;/h2&gt;

&lt;p&gt;No, it's not (just) magic. It's clever engineering backed by a service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Text is the Key:&lt;/strong&gt; When your component renders, the &lt;code&gt;&amp;lt;I18nKeyless&amp;gt;&lt;/code&gt; component (or its equivalent hook/HOC) grabs the raw text you wrote (e.g., "The Next Big Thing is Here!").&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Smart Backend:&lt;/strong&gt; This text, along with your API key and target languages, is sent to the &lt;code&gt;i18n-keyless&lt;/code&gt; service.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AI-Powered Translation:&lt;/strong&gt; If this specific text hasn't been translated into your target languages before (for your API key), the service generate high-quality translations on the fly.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Caching &amp;amp; Delivery:&lt;/strong&gt; These translations are then stored and served back to your app. Subsequent requests for the same text hit the cache for instant delivery.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Context Matters:&lt;/strong&gt; You can even provide context to ensure the translations are spot on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The beauty is, you, the developer, don't need to manage any of this complexity. You just write.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Isn't a "Later" Problem, It's a "Solved" Problem
&lt;/h2&gt;

&lt;p&gt;Forget the idea that you'll "add i18n later." With &lt;code&gt;i18n-keyless&lt;/code&gt;, you add it &lt;em&gt;now&lt;/em&gt;, without the traditional pain. It's not a placeholder; it's a robust, scalable solution from day one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;No "Translation Debt":&lt;/strong&gt; You're not accumulating a mountain of untranslated strings.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Instant Multi-Language Capability:&lt;/strong&gt; Want to support a new language? Add it to your &lt;code&gt;supported&lt;/code&gt; array in the config. The service takes care of backfilling translations.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Developer Bliss:&lt;/strong&gt; Your team focuses on building features in your primary language. The i18n just &lt;em&gt;happens&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Future is Keyless (and Less Painful)
&lt;/h2&gt;

&lt;p&gt;For too long, i18n has been a necessary evil, a speed bump in the development process. Tools like &lt;code&gt;i18n-keyless&lt;/code&gt; flip the script. By leveraging the text itself as the identifier and using AI for the heavy lifting, it removes the most tedious parts of internationalization.&lt;/p&gt;

&lt;p&gt;While the client-side SDK is open source and you &lt;em&gt;could&lt;/em&gt; build your own backend, the real power comes with the managed service at &lt;a href="https://i18n-keyless.com" rel="noopener noreferrer"&gt;i18n-keyless.com&lt;/a&gt;. This gives you access to the AI translation engine, robust caching, and a handy dashboard to monitor your usage, manage languages, and even tweak translations if needed. It’s designed to be a set-it-and-forget-it solution that scales with you.&lt;/p&gt;

&lt;p&gt;You save time, reduce cognitive load, and can genuinely build for a global audience from the get-go, even on a shoestring MVP budget.&lt;/p&gt;

&lt;p&gt;Ready to stop worrying about translation keys and start shipping faster?&lt;/p&gt;

&lt;p&gt;Give &lt;a href="https://github.com/arnaudambro/i18n-keyless" rel="noopener noreferrer"&gt;&lt;code&gt;i18n-keyless&lt;/code&gt;&lt;/a&gt; a spin and check out the service at &lt;a href="https://i18n-keyless.com" rel="noopener noreferrer"&gt;i18n-keyless.com&lt;/a&gt;. Your development workflow will thank you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r1q5sch3wqi3snjivrj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r1q5sch3wqi3snjivrj.png" alt="i18n-keyless dashboard for Niki Coach niki-coach.com"&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>react</category>
      <category>i18n</category>
      <category>productivity</category>
      <category>mvp</category>
    </item>
    <item>
      <title>Mastering and Taking advantage of React `key` prop</title>
      <dc:creator>Arnaud Ambroselli</dc:creator>
      <pubDate>Tue, 22 Mar 2022 11:40:54 +0000</pubDate>
      <link>https://dev.to/arnaudambro/mastering-and-taking-advantage-of-react-key-prop-2k21</link>
      <guid>https://dev.to/arnaudambro/mastering-and-taking-advantage-of-react-key-prop-2k21</guid>
      <description>&lt;p&gt;You might know that &lt;code&gt;key&lt;/code&gt; is a reserved prop in the React ecosystem. &lt;br&gt;
I also guess you've get acquainted to &lt;code&gt;key&lt;/code&gt; while learning how to &lt;a href="https://beta.reactjs.org/learn/rendering-lists#rules-of-keys"&gt;render a list&lt;/a&gt;, that you &lt;em&gt;have to&lt;/em&gt; give a unique key to a list of items - maybe you don't even know why, you just do it.&lt;/p&gt;

&lt;p&gt;Well, by understanding how this rendering thing works and why a unique &lt;code&gt;key&lt;/code&gt; is so important, you'll learn a new and very powerful way of using this &lt;code&gt;key&lt;/code&gt; prop, not even while rendering a list !&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the &lt;code&gt;key&lt;/code&gt; prop must be unique in a list
&lt;/h2&gt;

&lt;p&gt;React always try to optimise the rendering of components, by re-rendering only what changed between the previous state and the new. To do so, &lt;code&gt;key&lt;/code&gt; is one of the thing that tells react to recreate the element if the &lt;code&gt;key&lt;/code&gt; changed.&lt;/p&gt;

&lt;p&gt;If you render a list and you don't setup the &lt;code&gt;key&lt;/code&gt; prop yourself, React will automatically set the &lt;code&gt;key&lt;/code&gt; to be the &lt;code&gt;index&lt;/code&gt; of the item in the array. That's fine if this array is static and never changes, but if it does change, it's gonna be a problem : your item will never re-render, because its props didn't change, neither its state.&lt;/p&gt;

&lt;p&gt;What you should remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;When a component's state or props changes, React &lt;em&gt;re-render&lt;/em&gt; it&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When a component's key changes, React &lt;em&gt;re-create&lt;/em&gt;, with initial state and props&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When none of those change, React keep the component as is, &lt;em&gt;no re-render is happening&lt;/em&gt;.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why if the items of your list change, you need to set each of them a unique &lt;code&gt;key&lt;/code&gt;, so that when the &lt;code&gt;key&lt;/code&gt; changes, the component recreates itself and your list updates&lt;/p&gt;

&lt;h2&gt;
  
  
  How to take advantage of the &lt;code&gt;key&lt;/code&gt; prop outside a list
&lt;/h2&gt;

&lt;p&gt;Sometimes, a component needs to get its state reset to initial values. How to ?&lt;/p&gt;

&lt;p&gt;-&amp;gt; have a sort of &lt;code&gt;reset&lt;/code&gt; function that reset all states: that can be tedious, and sometimes mistaking&lt;br&gt;
-&amp;gt; change the &lt;code&gt;key&lt;/code&gt; prop of this component&lt;/p&gt;

&lt;p&gt;I'm a big fan of the second option that I use a lot around my project : it's only a few lines of code maximum, it's 100% efficient, no mistake possible.&lt;/p&gt;

&lt;p&gt;One of my colleague told me a few days ago: "That little hack is nice, but is it a proper way to do ?"&lt;/p&gt;

&lt;p&gt;Well, this hack is not my own creation, I've learned it from another dev, but I never checked if there were official guidelines for it, and guess what : now with the new React docs, it has !&lt;br&gt;
&lt;a href="https://beta.reactjs.org/apis/usestate#resetting-state-with-a-key"&gt;https://beta.reactjs.org/apis/usestate#resetting-state-with-a-key&lt;/a&gt;, by Dan Abramov himself.&lt;/p&gt;

&lt;p&gt;Have fun !&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy a Next.js static app in Clever Cloud</title>
      <dc:creator>Arnaud Ambroselli</dc:creator>
      <pubDate>Sat, 04 Dec 2021 16:58:49 +0000</pubDate>
      <link>https://dev.to/arnaudambro/deploy-a-nextjs-static-app-in-clever-cloud-iei</link>
      <guid>https://dev.to/arnaudambro/deploy-a-nextjs-static-app-in-clever-cloud-iei</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: This post is not sponsored by &lt;a href="https://www.clever-cloud.com"&gt;Clever Cloud&lt;/a&gt; by any mean, but it's a service I really like : great UX, great support, and made in Europe&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.clever-cloud.com"&gt;Clever Cloud&lt;/a&gt; is great, nevertheless it took me a small hour to deploy a static NextJS app the first time. But their support was really efficient and we sorted it out really fast ! Just by setting up the correct environment variables.&lt;/p&gt;

&lt;p&gt;Context: We're working on a monorepo, meaning that in a single github repository we have many folders such as &lt;code&gt;api&lt;/code&gt;, &lt;code&gt;app&lt;/code&gt;, &lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;dashboard&lt;/code&gt;, etc. So the NextJS app is located in the &lt;code&gt;app&lt;/code&gt; folder, that's all we need to know here.&lt;/p&gt;

&lt;p&gt;Back in Clever Cloud Console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new application&lt;/li&gt;
&lt;li&gt;Choose "Create from a Github Repository" and select your repo&lt;/li&gt;
&lt;li&gt;Step "What kind of application is it ?", select "Static", with a feather 🪶 as an icon&lt;/li&gt;
&lt;li&gt;Config your instances as you wish (Autoscalability, Horizontal scaling, Vertical scaling), name it as you wish, choose your region and create it&lt;/li&gt;
&lt;li&gt;Then go to "Environment variables" and setup the variables this way:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_FOLDER="app"
CC_CACHE_DEPENDENCIES="true"
CC_CGI_IMPLEMENTATION="proxy_fcgi"
CC_NODE_DEV_DEPENDENCIES="install"
CC_PRE_BUILD_HOOK="cd app &amp;amp;&amp;amp; npm install --also=dev &amp;amp;&amp;amp; npm run build"
CC_WEBROOT="/out"
HOST="0.0.0.0"
NEXT_PUBLIC_ANY_VARIABLES="{variables you defined for your project}"
NODE_ENV="production"
PORT="8080"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it !&lt;/p&gt;

&lt;p&gt;Clever Cloud moto is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Vous développez, nous déployons&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;You code, we deploy&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cannot be more true ! 🥸&lt;/p&gt;

</description>
    </item>
    <item>
      <title>9 Things You Should Do or Know Before Building Native Apps</title>
      <dc:creator>Arnaud Ambroselli</dc:creator>
      <pubDate>Sat, 04 Dec 2021 14:59:09 +0000</pubDate>
      <link>https://dev.to/arnaudambro/9-things-you-should-do-or-know-before-building-native-apps-1bac</link>
      <guid>https://dev.to/arnaudambro/9-things-you-should-do-or-know-before-building-native-apps-1bac</guid>
      <description>&lt;p&gt;TDLR;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Header &lt;code&gt;appversion&lt;/code&gt; for each request&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Header &lt;code&gt;appdevice&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Header &lt;code&gt;currentroute&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setup a pattern to display a message to your app on response to a backend request&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allow a user interaction/redirection from the backend&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send a request to your backend on each page change&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setup a Check Version and/or Force Update pattern&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep things in the backend if you can&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Beware of the version naming : a mistake is for life&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Building a iOS/Android/macOS/whatever native app is not the same as building a web app.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;With a web app running on browsers&lt;/strong&gt;, if you want to deploy another version of the app, you just do it and instantly all users get the latest release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But native app are packages &lt;em&gt;installed&lt;/em&gt; on your device&lt;/strong&gt; with a few consequences&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before a new version is available on the stores, it can take a few hours or even days because native apps are checked by the store maintainers.&lt;/li&gt;
&lt;li&gt;It might even be rejected because of whatever check done by the store managers didn't pass.&lt;/li&gt;
&lt;li&gt;You can't remove or cancel a release of your app. Once it's deployed on the stores, it's &lt;em&gt;for ever&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why before sending the first release of your app, you should setup a few safety measures in case something goes wrong with one of the available apps on the store. And believe me, chances are big that someday something will go wrong. At least once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things you should setup or know before sending a native app
&lt;/h2&gt;

&lt;p&gt;Let's consider you build an app with a backend and a database.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Header &lt;code&gt;appversion&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For each and every request to the backend, find a way for the backend to know the &lt;strong&gt;app version&lt;/strong&gt; in case you need to hotfix for specific versions of your app. Usually, I set a  &lt;code&gt;appversion: {my-app-version}&lt;/code&gt; in the Headers.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Header &lt;code&gt;appdevice&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Find also a way for the backend to know the &lt;strong&gt;device and/or OS&lt;/strong&gt; it's running on (android/ios), just in case. &lt;br&gt;
That's where I setup &lt;code&gt;appdevice: {my-app-device}&lt;/code&gt; in the Headers too.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Header &lt;code&gt;currentroute&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Less important, but still useful in some cases, send the current page / current route to your backend. You might not see how it could be useful now, but remember, once you find it useful and your app is already deployed in production, it's too late.&lt;br&gt;
I like headers, so I add a &lt;code&gt;currentroute: {the-current-route}&lt;/code&gt; in the headers too. &lt;/p&gt;
&lt;h3&gt;
  
  
  4. Setup a pattern to display a message to your app on response to a backend request
&lt;/h3&gt;

&lt;p&gt;Setup a way to be able to communicate to your app from the backend. For instance, I'm a JavaScript guy working with ExpressJS and React Native, and what I do in the front-end is, while I'm reading the &lt;code&gt;response&lt;/code&gt; from the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showAlert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Alert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showAlert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subtitle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;showAlert&lt;/code&gt; being an object of an &lt;a href="https://reactnative.dev/docs/alert"&gt;alert in react native&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Allow a user interaction/redirection from the backend
&lt;/h3&gt;

&lt;p&gt;Even more, within the &lt;code&gt;showAlert&lt;/code&gt; object, you can (and should) be able to redirect the user to anything you want if he presses &lt;code&gt;OK&lt;/code&gt; or &lt;code&gt;Cancel&lt;/code&gt; or whatever action you defined. &lt;br&gt;
For instance, I use &lt;a href="https://reactnavigation.org"&gt;React Navigation&lt;/a&gt; for navigating through the screens, therefore I usually add a &lt;code&gt;onOkRedirect&lt;/code&gt; field on the &lt;code&gt;showAlert&lt;/code&gt; object so that if this field exists, pressing on &lt;code&gt;OK&lt;/code&gt; will trigger &lt;code&gt;navigation.navigate(... onOkRedirect)&lt;/code&gt;. But you can add &lt;code&gt;onOkRedirectToUrl&lt;/code&gt; or anything in your mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Send a request to your backend on each page change
&lt;/h3&gt;

&lt;p&gt;I also like to send a request on each page change, so that if I have a bug in one of the page, or if I want to send specific in-app message for a particular screen, I can.&lt;br&gt;
In React Native and React Navigation, I listen to state change and send a request to the backend on each of the route changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Setup a Check Version and/or Force Update pattern
&lt;/h3&gt;

&lt;p&gt;Because you don't want the user to &lt;em&gt;have to&lt;/em&gt; download a new version every other day - it would be a cruel user experience - you might have to handle backward compatibility of your app in your backend. That's why &lt;code&gt;appversion&lt;/code&gt; is so useful. But sometimes, you want to get rid of technical debt linked to this extra code, or you also might have a breaking change, or whatever : you need to force the user to update to the last version. &lt;/p&gt;

&lt;p&gt;If you didn't plan it, it won't happen ! I see two options there&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;either you have a middleware in your backend that check the version on each request and send back a &lt;code&gt;showAlert&lt;/code&gt; to force the user to download the newest version of the app (and that's where the &lt;code&gt;appdevice&lt;/code&gt; header is useful to redirect the user to the good store)&lt;/li&gt;
&lt;li&gt;either you have a request with the path &lt;code&gt;/check-version&lt;/code&gt; located properly in your app so that if the version is not good, you have a beautifully designed screen inviting your user to download the new version of the app&lt;/li&gt;
&lt;li&gt;either both !&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Keep things in the backend if you can
&lt;/h3&gt;

&lt;p&gt;That's actually THE thing to remember while you're coding, together with the backward compatibility in mind.&lt;/p&gt;

&lt;p&gt;You can't have the whole app in the backend, and have it downloaded at every app load : you definitely need a part of the code in the app, and another one in the backend.&lt;/p&gt;

&lt;p&gt;But sometimes you hesitate : should I put this in the front or in the back ? When you &lt;em&gt;do&lt;/em&gt; hesitate, opt in for the backend : you can change the backend any time, you can't change the front end anymore. &lt;/p&gt;

&lt;p&gt;Think the native app as a displayer only, not a brain - live that part to the backend. &lt;/p&gt;

&lt;p&gt;I also tend to put i18n in the backend too : it's too sad to have to redeploy a whole app because of a typo somewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Beware of the version naming : a mistake is for life
&lt;/h3&gt;

&lt;p&gt;Last but not least...&lt;/p&gt;

&lt;p&gt;Android has a &lt;code&gt;versionName&lt;/code&gt; and a &lt;code&gt;versionCode&lt;/code&gt;, iOS has a &lt;code&gt;CURRENT_PROJECT_VERSION&lt;/code&gt; and a &lt;code&gt;MARKETING_VERSION&lt;/code&gt;, I don't know about the others : those need to be incremented when sending a new version to the stores. &lt;/p&gt;

&lt;p&gt;Be careful : if you made a typo by writing &lt;code&gt;20.0.1&lt;/code&gt; instead of &lt;code&gt;2.0.1&lt;/code&gt;, you won't be able to take it back, and from now on all the other version will &lt;em&gt;have to&lt;/em&gt; be greater than &lt;code&gt;20.0.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Be also careful : one is to be only a number (&lt;code&gt;CURRENT_PROJECT_VERSION&lt;/code&gt; and &lt;code&gt;versionCode&lt;/code&gt;), the other one is &lt;code&gt;{major}.{minor}.{patch}&lt;/code&gt;. If you make a mistake at the beginning, you also won't be able to take it back either. But don't worry too much about versioning here if you made a mistake : I think Facebook itself might have made a mistake as there are at version &lt;code&gt;345.0&lt;/code&gt; on the store.&lt;/p&gt;

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

&lt;p&gt;All of these tips are coming from mistakes I personally made. That's not small mistakes when you have a client to face with. Having an app in production is quite a journey : I hope I've helped you preparing it !&lt;/p&gt;

</description>
      <category>ios</category>
      <category>android</category>
      <category>app</category>
      <category>checklist</category>
    </item>
    <item>
      <title>Simplest Drag and Drop setup in React, in 10 lines of code with SortableJS</title>
      <dc:creator>Arnaud Ambroselli</dc:creator>
      <pubDate>Sat, 27 Nov 2021 14:36:37 +0000</pubDate>
      <link>https://dev.to/arnaudambro/simplest-drag-and-drop-setup-in-react-in-10-lines-of-code-with-sortablejs-3dmi</link>
      <guid>https://dev.to/arnaudambro/simplest-drag-and-drop-setup-in-react-in-10-lines-of-code-with-sortablejs-3dmi</guid>
      <description>&lt;h2&gt;
  
  
  TDLR
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/SortableJS/Sortable"&gt;SortableJS&lt;/a&gt; make things really easy !&lt;br&gt;
For those who just want the final result, here is the code and a demo just below&lt;/p&gt;
&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sortable&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sortablejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./style.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SortableGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gridRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortableJsRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-grid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;initData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onListChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;gridRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-grid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sortableJsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Sortable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gridRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;onEnd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;onListChange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;gridRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"gridDemo"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"grid-square"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;SortableGrid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Demo available &lt;a href="https://www.javolution.io/simple-dragging-grid-react/#demo"&gt;on my personal blog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  So many DragNDrop libs out int the react ecosystem...
&lt;/h2&gt;

&lt;p&gt;...and yet no easy solution for any of them !&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/atlassian/react-beautiful-dnd"&gt;React Beautiful Dnd&lt;/a&gt;: build by Atlassian for Trello, it's reliable BUT&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This library continues to be relied upon heavily by Atlassian products, but we are focused on other priorities right now and have no current plans for further feature development or improvements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and also, not so easy to setup for someone who just want easy drag and drop&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/react-grid-layout/react-grid-layout"&gt;React Grid Layout&lt;/a&gt;: quite easy to setup, and quite powerful also. But I wanted to be able to move items in a grid so that it takes the position of another item in the grid and the grid keeps the same shape at the end of the drag/drop action - the defauilt behavior of this lib being to "make space" for the dragged item and break the grid layout. After spending one hour on it, I still couldn't find the way to achieve my goal, I quit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;a href="https://react-dnd.github.io/react-dnd/about"&gt;React DND&lt;/a&gt;: it seems also a powerful lib, but the API is sooooo ccomplicated ! And you have to &lt;a href="https://react-dnd.github.io/react-dnd/docs/tutorial"&gt;read their tutorial&lt;/a&gt; to setup anything, which is also giving headaches... I tried to implement the API, but after 200 lines of coding and 1 hours spent, I was lost, I tried something else&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://www.npmjs.com/package/react-draggable"&gt;react-draggable&lt;/a&gt;: I must say I didn't see that one, and didn't try.&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://github.com/bmcmahen/react-grid-dnd"&gt;react-grid-dnd&lt;/a&gt;: it looked like an easy setup and exactly want I was looking for, but... it's not maintained, and not working with npm7+ because it has react 16 as a dependency. So I had all the code setup before installing the lib, and I was quite fed up and tired when I discovered I would need to change my npm version to use it, or do some tricks here and there...&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://github.com/SortableJS/react-sortablejs"&gt;react-sortablejs&lt;/a&gt;: I didn't try because it says as an introduction&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that this is not considered ready for production, as there are still a number of bugs being sent through.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I thought : damn, there &lt;em&gt;should&lt;/em&gt; be out there a JavaScript library doing the simple thing I've asked for ! And I saw in this last &lt;a href="https://github.com/SortableJS/react-sortablejs"&gt;react-sortablejs&lt;/a&gt; that it was a "React bindings to SortableJS".&lt;/p&gt;

&lt;p&gt;I went to look for &lt;a href="https://github.com/SortableJS/Sortable"&gt;SortableJS&lt;/a&gt;, clicked on the &lt;a href="https://sortablejs.github.io/Sortable/"&gt;demo&lt;/a&gt;, scrolled to the &lt;a href="http://sortablejs.github.io/Sortable/#grid"&gt;grid example&lt;/a&gt; which was doing &lt;em&gt;exactly&lt;/em&gt; the simple stuff I was looking for.&lt;/p&gt;

&lt;p&gt;I checked in the dev tools, there was nothing else than a &lt;code&gt;div#gridDemo&lt;/code&gt; and some &lt;code&gt;div.square-items&lt;/code&gt; inside. I checkd for &lt;code&gt;gridDemo&lt;/code&gt; in the source code, and found out the code for that example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Grid demo&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Sortable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gridDemo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ghostClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue-background-class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I couldn't believe it... only those three lines of code and that's it ?&lt;br&gt;
And the &lt;a href="https://github.com/SortableJS/Sortable#options"&gt;api&lt;/a&gt; looks straight forward too : the &lt;code&gt;onEnd&lt;/code&gt; function seems doing the job I needed.&lt;/p&gt;

&lt;p&gt;I had to try it by myself !&lt;/p&gt;
&lt;h2&gt;
  
  
  Start with a simple grid, and just add a few more lines
&lt;/h2&gt;

&lt;p&gt;I wrote the React initial code : an array of items display in a grid layout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sortable&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sortablejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./style.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SortableGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"gridDemo"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"grid-square"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;SortableGrid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then just added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one ref for the grid container&lt;/li&gt;
&lt;li&gt;one ref for the SortableJS element&lt;/li&gt;
&lt;li&gt;one Effect to initiate SortableJs&lt;/li&gt;
&lt;li&gt;one function to handle the drag and drop&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data-id&lt;/code&gt; to all of the items in the grid layout&lt;/li&gt;
&lt;li&gt;a bit of refacto to save the new layout in storage (or in your back-end most probably)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;so that the code would be the one I wrote at the beginning, and as you can see, it works !&lt;/p&gt;

</description>
      <category>dragndrop</category>
      <category>react</category>
      <category>sortablejs</category>
      <category>grid</category>
    </item>
    <item>
      <title>I don't like React Hooks</title>
      <dc:creator>Arnaud Ambroselli</dc:creator>
      <pubDate>Thu, 19 Mar 2020 05:21:00 +0000</pubDate>
      <link>https://dev.to/arnaudambro/i-don-t-like-react-hooks-51ba</link>
      <guid>https://dev.to/arnaudambro/i-don-t-like-react-hooks-51ba</guid>
      <description>&lt;p&gt;Let's go strait to the point : I don't like Hooks because they are not intuitive to me. &lt;/p&gt;

&lt;p&gt;Classes are &lt;em&gt;so&lt;/em&gt; intuitive that I love them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class App extends React.Component {
  state = {  }
  componentDidMount() {}
  componentDidUpdate(prevProps, prevState) {}
  componentWillUnmount()
  render(){
    return()
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's almost if there is a README to understand what's going on there.&lt;br&gt;
I became a developer at 30, two and a half years ago, and I started directly by learning &lt;a href="https://javascript30.com"&gt;#JavaScript30 by Wes Bos&lt;/a&gt;, then &lt;a href="https://reactforbeginners.com"&gt;React for Beginners&lt;/a&gt;. I knew nothing about programming : classes, whatever... but React was so straightforward to embrace that it was a pleasure.&lt;/p&gt;

&lt;p&gt;I can't say the same with hooks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const App = () =&amp;gt; {
  const [someState, setSomeState] = useState(initState)
  useEffect(() =&amp;gt; {
    return () =&amp;gt; {}
  }, [])
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, much less code I have to admit.&lt;br&gt;
&lt;code&gt;useState&lt;/code&gt; is easy to get, I also have to admit. For a simple functional component which needs a state, this is great. But for more complex component, actually I would say as soon as an equivalent of &lt;code&gt;componentDidMount&lt;/code&gt; is needed, I much prefer classes.&lt;/p&gt;

&lt;p&gt;After two projects and two months full time on hooks, I am still not confident how to clear a timeout, how to use an effect only on mount. I start to be confident on fetching async data in an effect, but that's it. OK, refs are quite straight forward, I also have no problem with them.&lt;br&gt;
But what about the &lt;code&gt;useCallback&lt;/code&gt; ? Sometimes, quite often, but not always, when I call a callback in my effect, I am forced by my linter to use &lt;code&gt;useCallback&lt;/code&gt;, and I couldn't tell you why some times yes and why some other times no. Maybe I need a few more weeks to be fluent in Hooks, but as I don't like them it might be more...&lt;/p&gt;

&lt;p&gt;I am working for the first time with a friend, on a hooks project for the last two months. My friend is chasing the code lines, to reduce them at max, and he is also chasing code readability. He is quite an experienced programmer, so I learn quite some stuff from him. He doesn't like redux, so I had to think without it, it was great. And he loves hooks, so I had to deal with them, no choice.&lt;/p&gt;

&lt;p&gt;And I'll remember two philosophical principles out of my bad experience with Hooks :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if a piece of code with less lines is less understandable than a piece of code with more lines, use it with more lines&lt;/li&gt;
&lt;li&gt;a good API is an API where the README is as small as possible, and the number of times the need of going back to the README is as little as possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sorry Dan, but from now on, I'll keep hooks for stateful simple functional components, like forms. But whenever I can, I will use classes.&lt;/p&gt;

</description>
      <category>react</category>
      <category>lifecycle</category>
      <category>hooks</category>
      <category>class</category>
    </item>
  </channel>
</rss>
