<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Osama Qarem</title>
    <description>The latest articles on Forem by Osama Qarem (@osamaqarem).</description>
    <link>https://forem.com/osamaqarem</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%2F113950%2F5a99a05e-17f2-49fb-9fb4-a55082868924.jpg</url>
      <title>Forem: Osama Qarem</title>
      <link>https://forem.com/osamaqarem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/osamaqarem"/>
    <language>en</language>
    <item>
      <title>Parsing Custom Dates in JS</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sun, 05 Sep 2021 21:14:49 +0000</pubDate>
      <link>https://forem.com/osamaqarem/parsing-custom-dates-in-js-3kl8</link>
      <guid>https://forem.com/osamaqarem/parsing-custom-dates-in-js-3kl8</guid>
      <description>&lt;p&gt;Recently at work we moved our iOS React Native app from &lt;a href="https://trac.webkit.org/wiki/JavaScriptCore"&gt;JSC&lt;/a&gt; to &lt;a href="https://reactnative.dev/docs/hermes"&gt;Hermes&lt;/a&gt; which became available for iOS as of &lt;a href="https://reactnative.dev/blog/2021/03/12/version-0.64"&gt;RN0.64&lt;/a&gt;. Previously we were using Hermes only on Android and it was working great. Now that Android and iOS run the same engine we have confidence that our JavaScript output for both platforms will be equal – they should work and fail in JS land in the same ways.&lt;/p&gt;

&lt;p&gt;One thing which immediately broke on iOS was our Apple Health integration (which of course is iOS only) – specifically when parsing dates for user activities on the JS side. The date string returned from Objective-C to JavaScript looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-08-31T17:00:00.000+0300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could parse this previously on JSC using &lt;code&gt;new Date()&lt;/code&gt; but for some reason it results in an &lt;code&gt;"Invalid Date"&lt;/code&gt; on Hermes. Turns out the problem was in the time zone offset. Hermes could only parse ISO dates containing a time zone offset in &lt;code&gt;±HH:mm&lt;/code&gt; format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+03:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but not in a format without a colon &lt;code&gt;±HHmm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+0300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading about &lt;a href="https://en.wikipedia.org/wiki/ISO_8601"&gt;ISO 8601&lt;/a&gt;, it seems that both formats would be correct. I've submitted an issue about this on &lt;a href="https://github.com/facebook/hermes/issues/588"&gt;facebook/hermes&lt;/a&gt; to get more information and apparently JavaScript implements a simplified version of ISO 8601 which doesn't specify the time zone offset without a colon:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/facebook/hermes/issues/588#issuecomment-913167322"&gt;@neildhar&lt;/a&gt;: Hi &lt;a class="mentioned-user" href="https://dev.to/osamaqarem"&gt;@osamaqarem&lt;/a&gt;, thanks for reporting this. Note that the JavaScript uses a simplified version of ISO 8601, and does not specify the format without the colon for the timezone. However, as you mentioned, most other engines seem to support it, so we probably should too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So until this gets fixed in Hermes we will need to implement a workaround. We used the custom date formatter from &lt;a href="https://day.js.org/en/"&gt;Day.js&lt;/a&gt; – a great library which we were already making use of in our codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parsing Custom Dates
&lt;/h2&gt;

&lt;p&gt;Day.js depends on &lt;code&gt;new Date()&lt;/code&gt; for parsing &lt;a href="https://github.com/iamkun/dayjs/blob/dev/src/index.js#L55-L75"&gt;under the hood&lt;/a&gt;. Meaning it would still fail to parse our date when running Hermes. A small bundle size is one of the main features of Day.js so the package ships with only core functionality. To extend its capabilities, we use &lt;a href="https://day.js.org/docs/en/plugin/plugin"&gt;plugins&lt;/a&gt;. And the one we need is &lt;strong&gt;&lt;a href="https://day.js.org/docs/en/plugin/custom-parse-format"&gt;CustomParseFormat&lt;/a&gt;:&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="nx"&gt;dayjs&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;dayjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;customParseFormat&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;dayjs/plugin/customParseFormat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customParseFormat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Quite straightforward.&lt;/p&gt;

&lt;p&gt;Now we just need to define our format. To give Dayjs the ability to parse our date, we need to tell it what our date looks like based on these defined formats, e.g.:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;YY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;Two-digit year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;YYYY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;Four-digit year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1-12&lt;/td&gt;
&lt;td&gt;The month, beginning at 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;01-12&lt;/td&gt;
&lt;td&gt;The month, 2-digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1-31&lt;/td&gt;
&lt;td&gt;The day of the month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;01-31&lt;/td&gt;
&lt;td&gt;The day of the month, 2-digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;H&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0-23&lt;/td&gt;
&lt;td&gt;The hour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;00-23&lt;/td&gt;
&lt;td&gt;The hour, 2-digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0-59&lt;/td&gt;
&lt;td&gt;The minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;00-59&lt;/td&gt;
&lt;td&gt;The minute, 2-digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ss&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;00-59&lt;/td&gt;
&lt;td&gt;The second, 2-digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SSS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;000-999&lt;/td&gt;
&lt;td&gt;The millisecond, 3-digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;+05:00&lt;/td&gt;
&lt;td&gt;The offset from UTC, ±HH:mm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ZZ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;+0500&lt;/td&gt;
&lt;td&gt;The offset from UTC, ±HHmm&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the &lt;a href="https://day.js.org/docs/en/display/format#list-of-all-available-formats"&gt;full reference here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our date looks like &lt;code&gt;2021-08-31T17:00:00.000+0300&lt;/code&gt;, so the format we need would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'T' here is a constant which would be present in the expected date string
YYYY-MM-DDTHH:mm:ss.SSSZZ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using our custom format:&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="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-08-31T17:00:00.000+0300&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;YYYY-MM-DDTHH:mm:ss.SSSZZ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// 2021-08-31T14:00:00.000Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works! And once the fix for Hermes is in, we can replace it with a regular JS date constructor call.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out the source code for &lt;a href="https://github.com/iamkun/dayjs/blob/dev/src/plugin/customParseFormat/index.js"&gt;CustomParseFormat&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;This article was cross-posted from my personal blog. Do &lt;a href="https://osamaqarem.com/?join=true"&gt;subscribe&lt;/a&gt; to me there!&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Uploading iOS apps with special characters to App Store Connect</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sun, 22 Aug 2021 12:10:53 +0000</pubDate>
      <link>https://forem.com/osamaqarem/uploading-ios-apps-with-special-characters-to-app-store-connect-60k</link>
      <guid>https://forem.com/osamaqarem/uploading-ios-apps-with-special-characters-to-app-store-connect-60k</guid>
      <description>&lt;p&gt;Suppose you have an Xcode project where the product name includes special characters like an umlaut 'ü':&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eI8fxyd3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7z090elfw60uj3xcvai.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eI8fxyd3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7z090elfw60uj3xcvai.jpg" alt='Using Xcode to create an iOS project with the product name set to "Dümmy".'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try to archive it and upload it to App Store Connect you might be faced with the following mysterious error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kwwfcQ4r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7o2gcgf19wqr94q6h1ke.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kwwfcQ4r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7o2gcgf19wqr94q6h1ke.jpg" alt='ERROR ITMS-90035: "Invalid Signature. A sealed resource is missing or invalid. The file at path [Dümmy.app/Dümmy] is not properly signed. Make sure you have signed your application with a distribution certificate, not an ad hoc certificate or a development certificate. Verify that the code signing settings in Xcode are correct at the target level (which override any values at the project level).'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ERROR ITMS-90035: "Invalid Signature. A sealed resource is missing or invalid. The file at path [Dümmy.app/Dümmy] is not properly signed. Make sure you have signed your application with a distribution certificate, not an ad hoc certificate or a development certificate. Verify that the code signing settings in Xcode are correct at the target level (which override any values at the project level).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This happens because the default Xcode configuration uses the same variable to set both the names of the &lt;code&gt;.app&lt;/code&gt; package and the &lt;code&gt;.ipa&lt;/code&gt; archive - both of which may not have special characters. And in this case it is set to "Dümmy".&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Info.plist&lt;/code&gt; file will have the following keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PRODUCT_NAME&lt;/code&gt;: the name of the &lt;code&gt;.app&lt;/code&gt; bundle and executable file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CFBundleName&lt;/code&gt;: the &lt;a href="https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundlename"&gt;app name&lt;/a&gt; when &lt;code&gt;CFBundleDisplayName&lt;/code&gt; isn't set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tricky part is &lt;code&gt;CFBundleName&lt;/code&gt; which is set to the value of &lt;code&gt;$(PRODUCT_NAME)&lt;/code&gt; by default. What Apple docs do not mention is that starting with Xcode 12 and beyond it also represents the &lt;code&gt;.ipa&lt;/code&gt; file name.&lt;/p&gt;

&lt;p&gt;The solution is to set both &lt;code&gt;PRODUCT_NAME&lt;/code&gt; and &lt;code&gt;CFBundleName&lt;/code&gt; to values with no special characters and to explicitly set the display name under &lt;em&gt;Project Navigator → General → Display Name&lt;/em&gt;. This will generate a new key &lt;code&gt;CFBundleDisplayName&lt;/code&gt; whose value will be preferred over &lt;code&gt;CFBundleName&lt;/code&gt; for the app name.&lt;/p&gt;

&lt;p&gt;Now you can keep the app name with special characters, but remove them from the file names for the app package and archive.&lt;/p&gt;




&lt;p&gt;This article was cross-posted from my personal blog. Do &lt;a href="https://osamaqarem.com/?join=true"&gt;subscribe&lt;/a&gt; to me there!&lt;/p&gt;

</description>
      <category>xcode</category>
      <category>reactnative</category>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>Bootstrapping a React Native App with Best Practices</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sun, 23 Aug 2020 05:06:29 +0000</pubDate>
      <link>https://forem.com/osamaqarem/bootstrapping-a-react-native-app-with-best-practices-3pfn</link>
      <guid>https://forem.com/osamaqarem/bootstrapping-a-react-native-app-with-best-practices-3pfn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Edit: While this was probably a decent template at the time – I no longer recommend using it today. For the latest and greatest check out &lt;a href="https://github.com/t3-oss/create-t3-turbo"&gt;create-t3-turbo&lt;/a&gt; or &lt;a href="https://solito.dev/"&gt;Solito&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're unaware, you can &lt;a href="https://github.com/react-native-community/cli/blob/master/docs/init.md#initializing-project-with-custom-template"&gt;create your own&lt;/a&gt; react native template to be consumed by the react native cli.&lt;/p&gt;

&lt;p&gt;Since I always end up referencing old projects for some code (e.g. navigators, automation scripts) I decided I to make one and save myself the headache.&lt;/p&gt;

&lt;p&gt;Anyway, I've been maintaining it for some time now and I'm quite happy with where it's at. I only got around to writing some docs this weekend though, which is why I feel this is a good time to share. I should also mention that it is using TypeScript.&lt;/p&gt;

&lt;p&gt;Check it out here! &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/osamaq/react-native-template"&gt;osamaq/react-native-template&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Thanks to the work by the authors of react-native-cli, using the template is as easy as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx react-native init MyApp &lt;span class="nt"&gt;--template&lt;/span&gt; @osamaq/react-native-template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you are &lt;strong&gt;just&lt;/strong&gt; starting to learn React Native or TypeScript, I don't actually recommend this template as it could be a bit overwhelming, unless you have a native iOS or Android background.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've put a lot of work into it, from applying best practices to writing boilerplate components/logic that you can build upon. More than anything, I love the automation scripts. Please go through the docs or codebase and let me know what you think!&lt;/p&gt;

&lt;p&gt;If you have questions or suggestions on how it could be improved or what you'd do differently, I'd really appreciate it. Thanks!&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>GPT-3: Programming in English</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sat, 25 Jul 2020 04:48:59 +0000</pubDate>
      <link>https://forem.com/osamaqarem/gpt-3-programming-in-english-4nnn</link>
      <guid>https://forem.com/osamaqarem/gpt-3-programming-in-english-4nnn</guid>
      <description>&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1284421499915403264-263" src="https://platform.twitter.com/embed/Tweet.html?id=1284421499915403264"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1284421499915403264-263');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1284421499915403264&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I know GPT-3 and similarly fascinating tech have a long way to go, but I want you to envision a future where we use GPT-3 for real. This is my opinion after entertaining that thought:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/COBOL" rel="noopener noreferrer"&gt;COBOL&lt;/a&gt; was meant to be friendly to non-programmers using English words and such, but in the end, it was still programming.&lt;/p&gt;

&lt;p&gt;At my workplace, people who are proficient at using &lt;a href="https://www.joget.org/" rel="noopener noreferrer"&gt;Joget &lt;/a&gt;(low/no code platform) are called Joget Developers. Just like there are Joget Developers, there will be people trained at giving instructions to the AI and using its platform; GPT-3 Developers.&lt;/p&gt;

&lt;p&gt;Using GPT-3 will still be programming. It will be coding in a language that uses English as its syntax. Let's consider that for a moment: Human spoken languages are less concise, less clear and more prone to misunderstanding. People will need to practice the right nouns, adjectives and verbs etc. to use when talking to GPT-3 to get the outcome they want. You would need to learn to "debug" your English sentences according to how GPT-3 understands it, and not according to what you really meant. Words and even sentences carry different meanings based on context.&lt;/p&gt;

&lt;p&gt;Some might argue &lt;em&gt;"they could create a simplified version of the English language that makes it easier to give instructions to GPT-3"&lt;/em&gt; - you just invented a programming language.&lt;/p&gt;

&lt;p&gt;With programming languages, you say what you mean and mean what you say. Learning a logical language is easier than learning English.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>React Native: Generating TypeScript Types for Environment Variables</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sun, 19 Apr 2020 10:02:01 +0000</pubDate>
      <link>https://forem.com/osamaq/react-native-generating-typescript-types-for-environment-variables-141d</link>
      <guid>https://forem.com/osamaq/react-native-generating-typescript-types-for-environment-variables-141d</guid>
      <description>&lt;p&gt;As a React Native developer, I use &lt;a href="https://github.com/luggit/react-native-config" rel="noopener noreferrer"&gt;react-native-config&lt;/a&gt; to manage different environments. I create &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.env.staging&lt;/code&gt;, and &lt;code&gt;.env.prod&lt;/code&gt; for development, staging and production at the root of my project.&lt;/p&gt;

&lt;p&gt;Assuming my .env file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BASE_URL=https://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I'm able to do:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BuildConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// https://localhost:8000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems good. Works fine. But not for me. There is no autocomplete. It's not typesafe. It's prone to human error that is only noticable it at runtime. &lt;/p&gt;

&lt;p&gt;Whenever I go back to native development with Android Studio I'd get jealous of that typesafe autocomplete. How can we get something like that for React Native?&lt;/p&gt;

&lt;p&gt;Let's get some understanding of how it works for Android first. &lt;a href="https://gradle.org/" rel="noopener noreferrer"&gt;Gradle&lt;/a&gt; is the build tool used for android's build system. Whenever the android app is built, a class is generated describing environment variables allowing for typesafe environment variable access.&lt;/p&gt;

&lt;p&gt;Here is an illustration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fosamaq.com%2Fimg%2Fandroid_buildconfig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fosamaq.com%2Fimg%2Fandroid_buildconfig.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To bring that experience to React Native, we need to make a type declaration file that describes our environment variables module. That will let typescript know how to autocomplete. With a single environment variable, it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .env&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-config&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://localhost:8000&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;BuildConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&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;BuildConfig&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now once we import react-native-config module, we should get autocomplete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fosamaq.com%2Fimg%2Fenv_autocomplete.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fosamaq.com%2Fimg%2Fenv_autocomplete.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that's not as good. We don't want to have to update our type declaration file manually!&lt;/p&gt;

&lt;p&gt;For that, I resorted to writing quite a lengthy Node.js script. In &lt;em&gt;cough-cough&lt;/em&gt; plain javascript:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&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;contents&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;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ASCII&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;envStaging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.env.staging&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ASCII&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;envProd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.env.prod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ASCII&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;envLines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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;envStagingLines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envStaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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;envProdLines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envProd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filteredEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvStaging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvProd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;// Assumption: all files have the same number of lines&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;envLines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envLines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envStagingLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envStagingLines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envProdLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envProdLines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filteredEnv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filteredEnv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envStagingLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envStagingLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filteredEnvStaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envStagingLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filteredEnvStaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envStagingLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envProdLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envProdLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filteredEnvProd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envProdLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filteredEnvProd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envProdLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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="nx"&gt;filteredEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvProd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvStaging&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;generate&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;filteredEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvProd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvStaging&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;envVariableNamesArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;envVariableValuesArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;filteredEnv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Assumption: the files we read are not just comments&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envPair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredEnv&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envStagingValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvStaging&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&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;envProdValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredEnvProd&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;envVariableNamesArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envPair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="nx"&gt;envVariableValuesArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;envPair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;envStagingValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;envProdValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Assumption: for every name/key there are 3 values (env, env.staging, env.prod)&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;valuesCursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;envVariableNamesArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;table&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;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;envVariableNamesArray&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="p"&gt;[]]&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPushCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while &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="nx"&gt;totalPushCount&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;valueToPush&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envVariableValuesArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;valuesCursor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;table&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valueToPush&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;table&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valueToPush&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;valuesCursor&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
      &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stringArrayMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nameValueArray&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nameValueArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valuesArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nameValueArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: `&lt;/span&gt;

    &lt;span class="nx"&gt;valuesArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;` | "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;string&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;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`declare module "react-native-config" {
  interface Env {
    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stringArrayMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
  }

  const Config: Env

  export default Config
}`&lt;/span&gt;

  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env.d.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, this script will read all 3 environment files and generate a &lt;code&gt;.env.d.ts&lt;/code&gt; describing the types. It will only work if all 3 .env files contain the same number of variables with the same names, which makes sense.&lt;/p&gt;

&lt;p&gt;At the root directory of my react native project, I created a scripts folder and placed it there. It looks like this &lt;code&gt;MyApp/scripts/generateEnvTypes.js&lt;/code&gt;. Next I added the following npm script to my package.json:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"generate-env-types": "node scripts/generateEnvTypes.js"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, whenever I update my environment variables, I simply run the npm script and a new type declarations file is automatically generated! 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fosamaq%2Fosamaq.com%2Fmaster%2Fstatic%2Fimg%2Fgenerate_types.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fosamaq%2Fosamaq.com%2Fmaster%2Fstatic%2Fimg%2Fgenerate_types.gif" alt="generate env types"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;PS: I'm maintaining a React Native &lt;a href="https://github.com/osamaq/react-native-template/" rel="noopener noreferrer"&gt;template with a lot of goodies&lt;/a&gt; like the one in the article.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>reactnative</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Automatic Versioning for React Native Apps</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sat, 18 Apr 2020 12:27:42 +0000</pubDate>
      <link>https://forem.com/osamaqarem/automatic-versioning-for-react-native-apps-2bf3</link>
      <guid>https://forem.com/osamaqarem/automatic-versioning-for-react-native-apps-2bf3</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;You need to update your app's version to 1.0.0:&lt;/p&gt;

&lt;p&gt;1. You open up &lt;code&gt;android/app/build.gradle&lt;/code&gt; to update the version and bump the build number.&lt;/p&gt;

&lt;p&gt;2. You do the same thing for iOS using Xcode because editing build configuration files directly is more error prone.&lt;/p&gt;

&lt;p&gt;3. You need to keep it all consistent, so you open up &lt;code&gt;package.json&lt;/code&gt; and update the version so the reference to the version shown to the user from the JS side is correct. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./package.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// 1.0.0&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;I feel so productive and happy!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Said no developer ever after going through that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The ideal experience is to update only a single version number. Here's what we're going to do:&lt;/p&gt;

&lt;p&gt;1. Use &lt;code&gt;npm version [patch|minor|major]&lt;/code&gt; to handle the JS package version (see &lt;a href="https://docs.npmjs.com/about-semantic-versioning" rel="noopener noreferrer"&gt;semantic versioning&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The JS version is our &lt;strong&gt;source of truth&lt;/strong&gt;. Therefore, the Android and iOS versions should match whatever the &lt;code&gt;package.json&lt;/code&gt; version is set to.&lt;/p&gt;

&lt;p&gt;2. Use fastlane to handle the Android and iOS sides.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://fastlane.tools/" rel="noopener noreferrer"&gt;fastlane&lt;/a&gt; is an amazing open source tool focused at automating Android and iOS tasks. It has a wide library of community developed plugins that can help us handle things like, &lt;em&gt;versioning&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;3. Combine the above 2 steps into a single npm script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;p&gt;We will use a fresh React Native project as a starting point:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx react-native init MyApp


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

&lt;/div&gt;

&lt;p&gt;Install fastlane if you do not already have it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Install the latest Xcode command line tools&lt;/span&gt;
xcode-select &lt;span class="nt"&gt;--install&lt;/span&gt;

&lt;span class="c"&gt;# Install fastlane using RubyGems&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;fastlane &lt;span class="nt"&gt;-NV&lt;/span&gt;

&lt;span class="c"&gt;# Alternatively using Homebrew&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;fastlane


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

&lt;/div&gt;

&lt;p&gt;Set up a fastlane directory and create an empty fastfile:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;MyApp
&lt;span class="nb"&gt;mkdir &lt;/span&gt;fastlane &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;fastlane 
&lt;span class="nb"&gt;touch &lt;/span&gt;Fastfile


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

&lt;/div&gt;

&lt;p&gt;We want to be able to run the &lt;code&gt;fastlane&lt;/code&gt; command from the root of our React Native project. Therefore we will install our versioning plugins from the root directory:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="c"&gt;# Install plugins&lt;/span&gt;
fastlane add_plugin increment_version_name increment_version_code load_json


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

&lt;/div&gt;

&lt;p&gt;Say 'yes' if it asks about creating a gemfile.&lt;/p&gt;

&lt;p&gt;The first two plugins are for handling the version, version code on android and the third one is for reading a JSON file (our &lt;code&gt;package.json&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, we are going to add our fastlane scripts. Copy the following to the fastfile at &lt;code&gt;fastlane/Fastfile&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s1"&gt;'Android: Increment versionCode and set versionName to package.json version.'&lt;/span&gt;
  &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;json_path: &lt;/span&gt;&lt;span class="s2"&gt;"./package.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;private_lane&lt;/span&gt; &lt;span class="ss"&gt;:inc_ver_and&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;increment_version_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;gradle_file_path: &lt;/span&gt;&lt;span class="s2"&gt;"./android/app/build.gradle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;increment_version_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;gradle_file_path: &lt;/span&gt;&lt;span class="s2"&gt;"./android/app/build.gradle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;version_name: &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'version'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;


  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s1"&gt;'iOS: Increment build number and set the version to package.json version.'&lt;/span&gt;
  &lt;span class="n"&gt;private_lane&lt;/span&gt; &lt;span class="ss"&gt;:inc_ver_ios&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;json_path: &lt;/span&gt;&lt;span class="s2"&gt;"./package.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;increment_build_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;xcodeproj: &lt;/span&gt;&lt;span class="s1"&gt;'./ios/'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'.xcodeproj'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;increment_version_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;xcodeproj: &lt;/span&gt;&lt;span class="s1"&gt;'./ios/'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'.xcodeproj'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;version_number: &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'version'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;


  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s1"&gt;'Bump build numbers, and set the version to match the pacakage.json version.'&lt;/span&gt;
  &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:bump&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;inc_ver_ios&lt;/span&gt;
    &lt;span class="n"&gt;inc_ver_and&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Next we are going to add the following scripts to our package.json for automatic patch, minor and major version bumps:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{ 
  "name": "MyApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint .",
    "bump-patch": "npm version patch --no-git-tag-version &amp;amp;&amp;amp; bundle exec fastlane bump",
    "bump-minor": "npm version minor --no-git-tag-version &amp;amp;&amp;amp; bundle exec fastlane bump",
    "bump-major": "npm version major --no-git-tag-version &amp;amp;&amp;amp; bundle exec fastlane bump",
},


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

&lt;/div&gt;

&lt;p&gt;The first part of the command will upate the JS package version without making a commit to the git repo. The second part will execute the fastlane bump command, which will automatically bump the android and iOS build numbers and update the version to match the JS side.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# npm&lt;/span&gt;
npm run bump-patch  

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn bump-patch


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Ff8i5lrH2aBA66eP4Z8%2Fgiphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Ff8i5lrH2aBA66eP4Z8%2Fgiphy.gif" alt="Version Bump Gif"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;PS: I'm maintaining a React Native &lt;a href="https://github.com/osamaq/react-native-template/" rel="noopener noreferrer"&gt;template with a lot of goodies&lt;/a&gt; like the one in the article.&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>fastlane</category>
      <category>version</category>
    </item>
    <item>
      <title>Advanced Async Logic with Redux Observable</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sun, 13 Oct 2019 02:22:36 +0000</pubDate>
      <link>https://forem.com/osamaqarem/advanced-async-logic-with-redux-observable-2beg</link>
      <guid>https://forem.com/osamaqarem/advanced-async-logic-with-redux-observable-2beg</guid>
      <description>&lt;p&gt;Imagine that you're building a social network for cats. To register, a cat has to be verified that they are who they say they are by uploading a selfie and a photo of its paw. Our backend runs both images through its FelineCatusML™ billion dollar machine learning model and helps us verify that the pawprint and face belong to the same furball by going through legal cat records. If we believe kitty is playing tricks, we will terminate the sign up process.&lt;/p&gt;

&lt;p&gt;For example, if a cat says that its a brown Munchkin called Peanut, but the backend returned &lt;code&gt;name: 'Peanut'&lt;/code&gt; for the selfie and &lt;code&gt;name: 'Sir Williams'&lt;/code&gt; for the pawprint, registration will fail as names must match.&lt;/p&gt;

&lt;p&gt;This is the flow of our imaginary app. Each step is a different page/screen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Cat takes paw photo (API call #1).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cat starts filling up form.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cat takes selfie (API call #2).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check the outcome of API calls #1 &amp;amp; #2 and determine if sign up is successful.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here are some optimistic assumptions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because the first API call happens first, it completes first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But in the real world, either one may complete first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The user will wait patiently staring at loading indicators while any API calls are running :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The user will want to be able to cancel whatever is happening on their screen whenever they want to. Especially cat users. Cats have very short attention spans and cannot stare at loading indicators for long.&lt;/p&gt;

&lt;p&gt;Our apps need to be able to handle process cancellation. That means stopping all operations that are no longer needed. Not only are those considered memory leaks, but they can lead to very unexpected behavior. Imagine if a cat goes through step 1, then cancels (API call #1 still running) then comes back and does step 1 again. You can rarely ever predict what a cat is up to. It would not be out of the question to assume that we now have 2 API calls racing to update the same piece of state. And we cannot guarantee which one will finish first. So what is our next state? &lt;em&gt;Unknown&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Of course, we could make the process not cancellable &lt;em&gt;"Either you finish this right now, or you exit my app/close the browser"&lt;/em&gt;. But that is not good user experience. We must aim for flexible applications. They are more pleasant to use.&lt;/p&gt;

&lt;p&gt;Our API calls are probably happening in our redux actions. Besides process cancellation, how can we be notified when our app is in the following state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both API calls #1 &amp;amp; #2 have successfully returned results that are non-errors (remember, both calls are happening concurrently).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How can we handle cancellation and order of completion elegantly without writing too much code that is hard to follow?&lt;/p&gt;

&lt;p&gt;We have options for Redux. There are several middleware for handling complex asynchronous logic well documented by the docs (best docs ever, by the way) &lt;a href="https://redux.js.org/faq/actions#what-async-middleware-should-i-use-how-do-you-decide-between-thunks-sagas-observables-or-something-else"&gt;[1]&lt;/a&gt;&lt;a href="https://redux.js.org/introduction/ecosystem#side-effects"&gt; [2]&lt;/a&gt;. You can actually use whichever one you are comfortable with to deal with similar and more complex challenges. I was heavily considering &lt;a href="https://redux-saga.js.org"&gt;Redux Saga&lt;/a&gt; as it is the most popular. But I am not as familiar with JavaScript generators as I am with RxJs, and so I went with &lt;a href="https://redux-observable.js.org"&gt;Redux Observable&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redux-Observable 🔁
&lt;/h2&gt;

&lt;p&gt;As you can probably tell from the name, this library makes use of observables, particularly from RxJs. In fact, the API of redux-observable is about 3-4 functions. Most of the code we will write will actually be from RxJs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🛑 If you are not familiar with Rx, then you will likely face difficulty following the code in this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://osamaq.com/promises-to-rxjs-observables/"&gt;Brief intro using promises&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rxjs.dev/guide/overview"&gt;Official&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With redux-observable we create &lt;em&gt;epics&lt;/em&gt;. An epic is a function that takes in two arguments. The first one is a stream of actions running through your reducers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Redux action payload shape.&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Actions stream. An observable that wraps a payload.&lt;/span&gt;
  &lt;span class="nx"&gt;actions$&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionsObservable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you dispatch an action, it runs through your reducers, then your epics. Usually, an epic is set to execute when a specific action type is dispatched.&lt;br&gt;
The second argument is the stream of our store's state. This means that an epic may access the store's current state. We won't need that here.&lt;/p&gt;

&lt;p&gt;To keep this article short, I'll leave installing and setting up the library to you, as you can follow the instructions on the &lt;a href="https://redux-observable.js.org/"&gt;official docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Epics 🔥
&lt;/h2&gt;

&lt;p&gt;Our API calls will happen in our epics. We want to execute the first API call as soon as we have the necessary data. Therefore, we will create separate epics for each API call.&lt;/p&gt;

&lt;p&gt;1. &lt;code&gt;getNameForPawEpic()&lt;/code&gt; will make the first API call.&lt;br&gt;
2. &lt;code&gt;getNameForFaceEpic()&lt;/code&gt; will make the second API call.&lt;/p&gt;

&lt;p&gt;We will also have a third epic:&lt;/p&gt;

&lt;p&gt;3. &lt;code&gt;verificationEpic()&lt;/code&gt; will run when &lt;em&gt;both&lt;/em&gt; epics above have dispatched success actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Action creator&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNameForPaw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pawPhotoBase64&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GET_NAME_FOR_PAW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pawPhotoBase64&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action creator is called from our component. The dispatched action runs through our reducers, but there is no match for its type therefore it does not change our store's state. Its purpose is to run our first epic which will be listening to its action type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Epic&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNameForPawEpic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions$&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GET_NAME_FOR_PAW&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://api.felinecatus.com/pawprint/verification&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;pawPhotoBase64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;pipe&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;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GET_NAME_FOR_PAW_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GET_NAME_FOR_PAW_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nx"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CANCEL&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
        &lt;span class="nx"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GET_NAME_FOR_PAW_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what is our epic doing? It is:&lt;/p&gt;

&lt;p&gt;1. Listening to a stream of actions using a redux-observable helper function &lt;code&gt;ofType()&lt;/code&gt; which filters by the type we specify.&lt;/p&gt;

&lt;p&gt;2. When &lt;code&gt;GET_NAME_FOR_PAW&lt;/code&gt; action is dispatched, the epic will let that action through.&lt;/p&gt;

&lt;p&gt;3. We &lt;code&gt;switchMap()&lt;/code&gt; our action. This is simply the safe choice when mapping async actions. Since we don't want this action somehow executing more than once at a time, it will 'switch' to the most recent call, and map the result to what follows.&lt;/p&gt;

&lt;p&gt;We destructure the payload from our action and create the API call using the &lt;code&gt;ajax()&lt;/code&gt; operator. We map the result to either success or error types. What is to be done with the error is to be handled by our component.&lt;/p&gt;

&lt;p&gt;Epics take in a stream of actions, and let out plain action objects. That is why we are returning action payloads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="c1"&gt;//  In&lt;/span&gt;
   &lt;span class="nx"&gt;action$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionsObservable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

   &lt;span class="c1"&gt;// Out. Passes through our reducers.&lt;/span&gt;
   &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;Action&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4. We have a an action type called &lt;code&gt;CANCEL&lt;/code&gt; which when dispatched, will cancel &lt;em&gt;all&lt;/em&gt; of our network requests. We might dispatch this when the user navigates away to cancel the process. This works because &lt;code&gt;takeUntil()&lt;/code&gt; is listening to the stream of actions and completes our ajax observable if the cancellation action type comes through.&lt;/p&gt;

&lt;p&gt;5. &lt;code&gt;catchError()&lt;/code&gt; does what its called. In case something unexpected happens, we can handle it here. It must return an observable though, that is why we use &lt;code&gt;of()&lt;/code&gt; on the action returned from within it.&lt;/p&gt;

&lt;p&gt;This is our action creator for our second epic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Action creator for second epic&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNameForFace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;facePhotoBase64&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GET_NAME_FOR_FACE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;facePhotoBase64&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code for &lt;code&gt;getNameForFaceEpic()&lt;/code&gt; is very similar to the first epic, except it listens to &lt;code&gt;GET_NAME_FOR_FACE&lt;/code&gt; and dispatches &lt;code&gt;GET_NAME_FOR_FACE_SUCCESS&lt;/code&gt; on success and &lt;code&gt;GET_NAME_FOR_FACE_ERROR&lt;/code&gt; on error. So we will stick to pretending that we have written it 🙂.&lt;/p&gt;

&lt;p&gt;Our first 2 epics combined act as the action creator of our third epic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Third epic&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verificationEpic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions$&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;paw$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GET_NAME_FOR_PAW_SUCCESS&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;face$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GET_NAME_FOR_FACE_SUCCESS&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;combined$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;face$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paw$&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;cancel$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CANCEL&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;combined$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&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;face&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paw&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;verifiedKitty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;paw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VERIFICATION_COMPLETE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;verifiedKitty&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cancel$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1. We create &lt;code&gt;paw$&lt;/code&gt; &amp;amp; &lt;code&gt;face$&lt;/code&gt; which are streams of actions filtered by the &lt;em&gt;success&lt;/em&gt; types of the first 2 epics.&lt;/p&gt;

&lt;p&gt;2. We combine those two using the zip operator which creates a new stream that emits a value only when both streams emit once. This way, we can get a success notification only when both succeed.&lt;/p&gt;

&lt;p&gt;3. When both API calls succeed, we process our payloads and map the output to &lt;code&gt;VERIFICATION_COMPLETE&lt;/code&gt; which runs through our reducers and updates our store's state. Our component handles the outcome.&lt;/p&gt;

&lt;p&gt;In case one epic sends off the success action, our &lt;code&gt;combined$&lt;/code&gt; stream will now wait for the other pair to emit its success action. In case the user cancelled the process or an error in the other request ocurred, no success actions are going to happen. Therefore, we need to be able to reset our &lt;code&gt;combined$&lt;/code&gt; stream to listen to both success actions again.&lt;/p&gt;

&lt;p&gt;4. We do &lt;code&gt;takeUntil(cancel$)&lt;/code&gt;. This will complete our observable returned by our epic when the &lt;code&gt;CANCEL&lt;/code&gt; type comes through. Since we completed the outermost observable in our epic, it is now dead and no longer working.&lt;/p&gt;

&lt;p&gt;5. To remedy this, we pipe the &lt;code&gt;repeat()&lt;/code&gt; operator, which restarts our &lt;code&gt;combined$&lt;/code&gt; observable as soon as it completes making it listen to both &lt;code&gt;face$&lt;/code&gt; and &lt;code&gt;paw$&lt;/code&gt; from square one again.&lt;/p&gt;




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

&lt;p&gt;Cancellable, flexible and concise async process management ✅ with redux. And we've only used a few RxJs operators. Remember, You can use more than one redux middleware at the same time. I am still using redux-thunk alongside redux-observable. Simple problems should still be solved with simple solutions.&lt;/p&gt;

&lt;p&gt;Thank you for reading. I hope you found this useful.&lt;/p&gt;

</description>
      <category>redux</category>
      <category>rxjs</category>
      <category>react</category>
      <category>state</category>
    </item>
    <item>
      <title>Thinking in React for Native Android Apps</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Fri, 20 Sep 2019 13:50:50 +0000</pubDate>
      <link>https://forem.com/osamaq/thinking-in-react-for-native-android-apps-40h0</link>
      <guid>https://forem.com/osamaq/thinking-in-react-for-native-android-apps-40h0</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally published on my personal &lt;a href="https://osamaq.com/thinking-in-react-for-writing-native-android-apps/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I like writing apps using React Native. In contrast, working on Java Android apps has always been less satisfying because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Boilerplate.&lt;/li&gt;
&lt;li&gt;ConstraintLayout? LinearLayout? RelativeLayout? TableLayout? GridLayout?&lt;/li&gt;
&lt;li&gt;&lt;a href="https://i.stack.imgur.com/fRxIQ.png" rel="noopener noreferrer"&gt;???&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's a simple fact that the more code you write, the more likely you are to write bugs. I knew using Kotlin would improve this aspect, but I wanted to get more experienced with Java, so that I'd better appreciate Kotlin when I made the move. I also didn't believe that just by using Kotlin, I'd suddenly really enjoy developing native apps.&lt;/p&gt;

&lt;p&gt;Recently, I came across &lt;a href="https://github.com/airbnb/MvRx/wiki" rel="noopener noreferrer"&gt;MvRx (Mavericks)&lt;/a&gt;. An Android framework &lt;a href="https://medium.com/airbnb-engineering/introducing-mvrx-android-on-autopilot-552bca86bd0a" rel="noopener noreferrer"&gt;open-sourced&lt;/a&gt; by Airbnb. I learned that it is conceptually &lt;a href="https://github.com/airbnb/MvRx/wiki#mvrx-for-react-engineers" rel="noopener noreferrer"&gt;inspired by React&lt;/a&gt; which piqued my interest. It even brings over the familiar &lt;code&gt;setState()&lt;/code&gt; syntax. Since MvRx is Kotlin-only, it tipped me over to start learning Kotlin.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The same todo app written using MvRx is about &lt;a href="https://github.com/airbnb/MvRx/tree/master/todomvrx" rel="noopener noreferrer"&gt;1000 lines of code &lt;em&gt;less&lt;/em&gt; than the same app written in Java&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Syntax-wise &lt;a href="https://gi-no.github.io/kotlin-is-like-typescript/" rel="noopener noreferrer"&gt;Kotlin has many similarties to TypeScript&lt;/a&gt; which I've always preferred using. I learned by going through the Kotlin official docs (which are awesome) and doing some of the the &lt;a href="https://play.kotlinlang.org/koans/overview" rel="noopener noreferrer"&gt;Kotlin Koans&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They say that no Java developer has tried Kotlin and wanted to go back to writing Java. I concur.&lt;/p&gt;

&lt;p&gt;I previously used &lt;a href="https://github.com/osamaq/android-mvp-tutorial" rel="noopener noreferrer"&gt;MVP architecture&lt;/a&gt;, whereas MvRx is MVVM. Presenters and ViewModels harbour the logic of your screens (similar to container components in React). The main difference between them is that a ViewModel never holds a reference to any view. It simply updates its state and the view observes the data changes and much like React, re-renders accordingly. Therefore, there is no fear of referencing a &lt;code&gt;null&lt;/code&gt; view (similar to calling &lt;code&gt;setState()&lt;/code&gt; on an unmounted React component). This greatly simplifies dealing with view lifecycles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FxiAMXpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FxiAMXpf.png" alt="Lifecycle vs ViewModel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During my process of learning MvRx and Kotlin, I came across a few helper libraries that improve development experience. I decided to learn and use them.&lt;/p&gt;

&lt;p&gt;I slowly came to the realization that sometimes, we might not enjoy working with a framework not because of the framework itself, but simply because of the way we apply it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Guide
&lt;/h2&gt;

&lt;p&gt;We're going to make a simple app utilizing the following libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigation Component&lt;/li&gt;
&lt;li&gt;Kotlin Android Extensions&lt;/li&gt;
&lt;li&gt;MvRx&lt;/li&gt;
&lt;li&gt;Flexbox Layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app flow will be as such:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login Screen:

&lt;ul&gt;
&lt;li&gt;Two text input fields.&lt;/li&gt;
&lt;li&gt;Login button.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the user presses the login button, we will mock a request using a simple delay. During the mock request, we will hide the view and show a loading indicator. Once the request is done, we will restore our view, hide the loading indicator and navigate to the landing screen.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Landing Screen:

&lt;ul&gt;
&lt;li&gt;This screen will simply show the data entered in the previous text inputs and a logout button.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Simple enough.&lt;/p&gt;

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

&lt;p&gt;Let's start by creating a blank Android Studio project with Kotlin and add our dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fbj81gfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fbj81gfn.png" alt="New android studio project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add MvRx and the navigation component to your dependencies block, under &lt;code&gt;app/build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
    def navVersion = "2.1.0"
    def mvrxVersion = '1.1.0'

    // Navigation component
    implementation "androidx.navigation:navigation-fragment-ktx:$navVersion"
    implementation "androidx.navigation:navigation-ui-ktx:$navVersion"

    // MvRx
    implementation "com.airbnb.android:mvrx:$mvrxVersion"

    // Flexbox
    implementation 'com.google.android:flexbox:1.1.0'
    ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the top of the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Kotlin Android Extensions
apply plugin: 'kotlin-android-extensions'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layouts
&lt;/h3&gt;

&lt;p&gt;We will use &lt;strong&gt;single activity - multiple fragments&lt;/strong&gt; pattern. Fragments should be designed as resuable and modular components, just like presentational components in React. &lt;/p&gt;

&lt;p&gt;Create our layout files: Right-click the &lt;code&gt;res&lt;/code&gt; folder then select &lt;strong&gt;New &amp;gt; Android Resource File&lt;/strong&gt;. Set the type as &lt;code&gt;Layout&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXdkq8hp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXdkq8hp.png" alt="Layout files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;activity_main.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;LinearLayout&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:orientation=&lt;/span&gt;&lt;span class="s"&gt;"vertical"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/host"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/LinearLayout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;login_fragment.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#F1F1F1"&amp;gt;

    &amp;lt;com.google.android.flexbox.FlexboxLayout

        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:layout_marginTop="200dp"
        app:alignItems="center"
        app:flexWrap="wrap"
        app:justifyContent="center"&amp;gt;

        &amp;lt;EditText
            android:id="@+id/loginNameText"
            android:layout_width="120dp"
            android:layout_height="60dp"
            android:hint="Name"
            android:importantForAutofill="no"
            android:inputType="text"
            app:layout_flexBasisPercent="80%"
            tools:text="Name" /&amp;gt;

        &amp;lt;EditText
            android:id="@+id/loginCityText"
            android:layout_width="120dp"
            android:layout_height="60dp"
            android:hint="City"
            android:importantForAutofill="no"
            android:inputType="text"
            app:layout_flexBasisPercent="80%"
            tools:text="City" /&amp;gt;

        &amp;lt;Button
            android:id="@+id/loginButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:backgroundTint="#6200EE"
            android:text="LOGIN"
            android:textColor="#FFF"
            app:layout_flexBasisPercent="80%" /&amp;gt;

        &amp;lt;ProgressBar
            android:id="@+id/loadingIndicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            app:layout_flexBasisPercent="100%"
            /&amp;gt;

    &amp;lt;/com.google.android.flexbox.FlexboxLayout&amp;gt;


&amp;lt;/FrameLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root is a &lt;code&gt;&amp;lt;FrameLayout/&amp;gt;&lt;/code&gt;. The &lt;code&gt;&amp;lt;fragment/&amp;gt;&lt;/code&gt; tag in &lt;code&gt;activity_main.xml&lt;/code&gt; will be swapped for the contents (children) of &lt;code&gt;&amp;lt;FrameLayout/&amp;gt;&lt;/code&gt; in each of our fragments. (a bit like React's &lt;a href="https://stackoverflow.com/questions/49706823/what-is-this-props-children-and-when-you-should-use-it" rel="noopener noreferrer"&gt;children&lt;/a&gt;?)&lt;/p&gt;

&lt;p&gt;The child of the root layout is &lt;a href="https://github.com/google/flexbox-layout" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;FlexboxLayout/&amp;gt;&lt;/code&gt;&lt;/a&gt;. Pretty cool. &lt;a href="https://developer.android.com/training/constraint-layout" rel="noopener noreferrer"&gt;&lt;code&gt;ConstraintLayout&lt;/code&gt;&lt;/a&gt; is nice if you prefer to customize the layout visually. &lt;/p&gt;

&lt;p&gt;Feel free to use whatever you fancy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FEoOCcJI.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FEoOCcJI.png" alt="Login fragment layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;landing_fragment.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;FrameLayout&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:background=&lt;/span&gt;&lt;span class="s"&gt;"#F1F1F1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;com.google.android.flexbox.FlexboxLayout&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"250dp"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_marginTop=&lt;/span&gt;&lt;span class="s"&gt;"200dp"&lt;/span&gt;
        &lt;span class="na"&gt;app:alignItems=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
        &lt;span class="na"&gt;app:flexWrap=&lt;/span&gt;&lt;span class="s"&gt;"wrap"&lt;/span&gt;
        &lt;span class="na"&gt;app:justifyContent=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:gravity=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
            &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@android:color/black"&lt;/span&gt;
            &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"24sp"&lt;/span&gt;
            &lt;span class="na"&gt;app:layout_flexBasisPercent=&lt;/span&gt;&lt;span class="s"&gt;"50%"&lt;/span&gt;
            &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"Name:"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/landingNameText"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:gravity=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
            &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@android:color/black"&lt;/span&gt;
            &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"24sp"&lt;/span&gt;
            &lt;span class="na"&gt;app:layout_flexBasisPercent=&lt;/span&gt;&lt;span class="s"&gt;"50%"&lt;/span&gt;
            &lt;span class="na"&gt;tools:text=&lt;/span&gt;&lt;span class="s"&gt;"placeholder"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:gravity=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
            &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@android:color/black"&lt;/span&gt;
            &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"24sp"&lt;/span&gt;
            &lt;span class="na"&gt;app:layout_flexBasisPercent=&lt;/span&gt;&lt;span class="s"&gt;"50%"&lt;/span&gt;
            &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"City:"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;TextView&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/landingCityText"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:gravity=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
            &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"@android:color/black"&lt;/span&gt;
            &lt;span class="na"&gt;android:textSize=&lt;/span&gt;&lt;span class="s"&gt;"24sp"&lt;/span&gt;
            &lt;span class="na"&gt;app:layout_flexBasisPercent=&lt;/span&gt;&lt;span class="s"&gt;"50%"&lt;/span&gt;
            &lt;span class="na"&gt;tools:text=&lt;/span&gt;&lt;span class="s"&gt;"placeholder"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;


        &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/logoutButton"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
            &lt;span class="na"&gt;android:layout_marginTop=&lt;/span&gt;&lt;span class="s"&gt;"30dp"&lt;/span&gt;
            &lt;span class="na"&gt;android:backgroundTint=&lt;/span&gt;&lt;span class="s"&gt;"#F05E54"&lt;/span&gt;
            &lt;span class="na"&gt;android:text=&lt;/span&gt;&lt;span class="s"&gt;"LOGOUT"&lt;/span&gt;
            &lt;span class="na"&gt;android:textColor=&lt;/span&gt;&lt;span class="s"&gt;"#FFF"&lt;/span&gt;
            &lt;span class="na"&gt;app:layout_flexBasisPercent=&lt;/span&gt;&lt;span class="s"&gt;"80%"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/com.google.android.flexbox.FlexboxLayout&amp;gt;&lt;/span&gt;


&lt;span class="nt"&gt;&amp;lt;/FrameLayout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FiTUjrWC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FiTUjrWC.png" alt="Landing fragment layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Classes
&lt;/h3&gt;

&lt;p&gt;Create our Kotlin classes to associate with each layout.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4dq3iEl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4dq3iEl.png" alt="Classes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create an activity, we would usually extend the &lt;code&gt;AppCompatActivity&lt;/code&gt; class directly. But since we want to use MvRx, we will extend &lt;code&gt;BaseMvRxActivity&lt;/code&gt; instead (which inherits from &lt;code&gt;AppCompatActivity&lt;/code&gt;) for MvRx support. We will also override &lt;code&gt;onCreate()&lt;/code&gt; and inflate &lt;code&gt;activity_main.xml&lt;/code&gt; here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: &lt;a href="https://developers.google.com/android/for-all/vocab-words/?hl=en" rel="noopener noreferrer"&gt;here&lt;/a&gt; is a super useful page for looking up Android lingo like 'inflate'.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;MainActivity.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.mymvrxapp&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.os.Bundle&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.airbnb.mvrx.BaseMvRxActivity&lt;/span&gt;


&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseMvRxActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every activity must be registered in the manifest. We will register &lt;code&gt;MainActivity&lt;/code&gt; and set it as the starting activity.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AndroidManifest.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;package=&lt;/span&gt;&lt;span class="s"&gt;"com.example.mymvrxapp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;
        &lt;span class="na"&gt;android:allowBackup=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;android:icon=&lt;/span&gt;&lt;span class="s"&gt;"@mipmap/ic_launcher"&lt;/span&gt;
        &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"@string/app_name"&lt;/span&gt;
        &lt;span class="na"&gt;android:roundIcon=&lt;/span&gt;&lt;span class="s"&gt;"@mipmap/ic_launcher_round"&lt;/span&gt;
        &lt;span class="na"&gt;android:supportsRtl=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;android:theme=&lt;/span&gt;&lt;span class="s"&gt;"@style/AppTheme"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.example.mymvrxapp.MainActivity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our fragments, we will extend &lt;code&gt;BaseMvRxFragment&lt;/code&gt; instead of &lt;code&gt;Fragment&lt;/code&gt;. We must also implement &lt;code&gt;invalidate()&lt;/code&gt;. We will leave it empty for and go over it later on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LoginFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.mymvrxapp&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.os.Bundle&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.LayoutInflater&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.View&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.ViewGroup&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.airbnb.mvrx.BaseMvRxFragment&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseMvRxFragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LayoutInflater&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewGroup&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
        &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;View&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="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login_fragment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LandingFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.mymvrxapp&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.os.Bundle&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.LayoutInflater&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.View&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.ViewGroup&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.airbnb.mvrx.BaseMvRxFragment&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LandingFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseMvRxFragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LayoutInflater&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewGroup&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
        &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;View&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="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;landing_fragment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Navigation
&lt;/h3&gt;

&lt;p&gt;If we run the app at this point, its going to crash. Our &lt;code&gt;&amp;lt;fragment/&amp;gt;&lt;/code&gt; in &lt;code&gt;activity_main.xml&lt;/code&gt; needs an ID and a name to associate it with a fragment. We've given it an ID but we haven't told it what fragment its going to host yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FbwalFSz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FbwalFSz.png" alt="Fragment name prop"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're not going to do this. Instead, we are going to associate it with our navigation graph. using the &lt;a href="https://developer.android.com/guide/navigation/" rel="noopener noreferrer"&gt;Navigation Component&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Simply put, it's a library that simplifies how we handle navigation with a neat API and a friendly interface to visualize our routes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The navigation component fulfills the same job as &lt;a href="https://reactnavigation.org/" rel="noopener noreferrer"&gt;React Navigation&lt;/a&gt; and &lt;a href="https://reacttraining.com/react-router/" rel="noopener noreferrer"&gt;React Router&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fun React Navigation Fact: We can &lt;a href="(https://reactnavigation.org/docs/en/react-native-screens.html)"&gt;configure&lt;/a&gt; it to use FragmentActivity&lt;br&gt;
instead of plain &lt;code&gt;View&lt;/code&gt;'s under the hood for performance improvements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create our navigation graph. Right-click the &lt;code&gt;res&lt;/code&gt; folder and then select &lt;strong&gt;New &amp;gt; Android Resource File&lt;/strong&gt;. Set the type as &lt;code&gt;Navigation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nav_graph.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_graph"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've created the file for our navigation graph, we will add an ID to &lt;code&gt;&amp;lt;fragment/&amp;gt;&lt;/code&gt; and designate it as our navigation host by adding the following attributes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;activity_main.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;LinearLayout&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:orientation=&lt;/span&gt;&lt;span class="s"&gt;"vertical"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/host"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"androidx.navigation.fragment.NavHostFragment"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
        &lt;span class="na"&gt;app:defaultNavHost=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;app:navGraph=&lt;/span&gt;&lt;span class="s"&gt;"@navigation/nav_graph"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/LinearLayout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets add our fragment classes to the navigation graph to mark them as possible destinations. I like to use the visual editor for this part. &lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;nav_graph.xml&lt;/code&gt; in the visual editor, and add &lt;code&gt;LoginFragment&lt;/code&gt; and &lt;code&gt;LandingFragment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FJHOwaX8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FJHOwaX8.png" alt="Adding destinations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the login fragment in the graph then click the home icon to mark it as the starting destination. &lt;/p&gt;

&lt;p&gt;Next, drag from the edge of the login fragment to the landing fragment to create a navigation action. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fa80Zbq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fa80Zbq5.png" alt="Route"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your navigation graph and markup should look similar to this. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;nav_graph.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_graph"&lt;/span&gt;
    &lt;span class="na"&gt;app:startDestination=&lt;/span&gt;&lt;span class="s"&gt;"@id/loginFragment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/landingFragment"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.example.mymvrxapp.LandingFragment"&lt;/span&gt;
        &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"LandingFragment"&lt;/span&gt;
        &lt;span class="na"&gt;tools:layout=&lt;/span&gt;&lt;span class="s"&gt;"@layout/landing_fragment"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/loginFragment"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.example.mymvrxapp.LoginFragment"&lt;/span&gt;
        &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"LoginFragment"&lt;/span&gt;
        &lt;span class="na"&gt;tools:layout=&lt;/span&gt;&lt;span class="s"&gt;"@layout/login_fragment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/action_loginFragment_to_landingFragment2"&lt;/span&gt;
            &lt;span class="na"&gt;app:destination=&lt;/span&gt;&lt;span class="s"&gt;"@id/landingFragment"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fragment&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/navigation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've added &lt;code&gt;tools:layout=...&lt;/code&gt; attribute for displaying your layouts in the navigation graph, otherwise you'd only see a plain and boring rectangle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnAWcI9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnAWcI9o.png" alt="Nav graph complete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we run the app now, we should see the Login screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logic
&lt;/h3&gt;

&lt;p&gt;Lets start by adding state to our text inputs. We need to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create our data class which describes the shape of our state.&lt;/li&gt;
&lt;li&gt;Create our view model class which will hold functions that trigger our state changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I created both the data class and the view model in the same file as &lt;code&gt;MainActivity.kt&lt;/code&gt; for convenience but that is not a requirement.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FormState&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;FormState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;loggedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Uninitialized&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MvRxState&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must set the initial state by providing default arguments. Notice it implements &lt;code&gt;MvRxState&lt;/code&gt;. That's required for any data class we wish to use as state.&lt;/p&gt;

&lt;p&gt;In React, we might have a &lt;code&gt;loading&lt;/code&gt; state and set it before and after the completion of asynchronous tasks. In MvRx, &lt;a href="https://github.com/airbnb/MvRx/wiki#async" rel="noopener noreferrer"&gt;&lt;code&gt;Async&lt;/code&gt;&lt;/a&gt; is a &lt;a href="https://kotlinlang.org/docs/reference/sealed-classes.html" rel="noopener noreferrer"&gt;sealed class&lt;/a&gt; that comes with types like &lt;code&gt;Loading&lt;/code&gt; and &lt;code&gt;Success&lt;/code&gt;. We can simply refer to the current type of the async value to react to loading and success states. Super helpful.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FormViewModel&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FormViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FormState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nc"&gt;BaseMvRxViewModel&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debugMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BuildConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;logStateChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setNameAndCity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// We will go over this one in depth later on&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;doLogIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Single&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delaySubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Schedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidSchedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mainThread&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&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;fun&lt;/span&gt; &lt;span class="nf"&gt;doLogout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Uninitialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;debugMode = BuildConfig.DEBUG&lt;/code&gt; will make some &lt;a href="https://github.com/airbnb/MvRx/wiki#debug-checks" rel="noopener noreferrer"&gt;safety checks&lt;/a&gt; when working with the debug build. The &lt;code&gt;init&lt;/code&gt; block and &lt;code&gt;logStateChanges()&lt;/code&gt; are also optional. &lt;code&gt;logStateChanges()&lt;/code&gt; does exactly what it says. We will show its output when we finish our app.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;setState&lt;/code&gt; reducers will be called from our views to update the state. Similar to React, the &lt;code&gt;setState&lt;/code&gt; block is an async operation and a pure function that takes in the current state, and returns the new state.&lt;/p&gt;

&lt;p&gt;Notice the &lt;code&gt;copy()&lt;/code&gt; syntax within the &lt;code&gt;setState&lt;/code&gt; block. Inside &lt;code&gt;setState&lt;/code&gt;, &lt;code&gt;this&lt;/code&gt; keyword would be our data class and &lt;code&gt;copy()&lt;/code&gt; is a &lt;a href="https://kotlinlang.org/docs/reference/data-classes.html#copying" rel="noopener noreferrer"&gt;method&lt;/a&gt; that belongs to data classes in Kotlin. It allows you to modify select properties instead of all (we don't need to spread the current state, in React lingo).&lt;/p&gt;

&lt;p&gt;Next, we want to be able to access state from our fragments. Our login and landing fragments must subscribe to the same view model &lt;em&gt;instance&lt;/em&gt; we defined in our main activity.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LoginFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseMvRxFragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fetch the ViewModel scoped to the current activity or create one if it doesn't exist&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FormViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;activityViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="o"&gt;..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LandingFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LandingFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseMvRxFragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="c1"&gt;// Fetch the existing ViewModel scoped to the current activity&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FormViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;existingViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="o"&gt;..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice &lt;code&gt;by activityViewModel()&lt;/code&gt;. It is a Kotlin &lt;a href="https://kotlinlang.org/docs/reference/delegated-properties.html" rel="noopener noreferrer"&gt;delegate&lt;/a&gt; that lazily returns a view model scoped to the current activity. Since both of our fragments belong to the same activity, sharing state is very straightforward.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;LandingFragment.kt&lt;/code&gt;, we used &lt;code&gt;existingViewModel()&lt;/code&gt; which returns the existing view model in scope of the current activity. The difference is that this function will throw an exception if no view model exists, instead of creating a new one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MvRx lets you &lt;a href="https://github.com/airbnb/MvRx/wiki#creating-and-subscribing-to-a-viewmodel" rel="noopener noreferrer"&gt;easily choose the scope&lt;/a&gt; of the view model you'd like to work with.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;As soon as our view loads (React: mounts), we're going to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a click listener to our login button.&lt;/li&gt;
&lt;li&gt;When the user presses the button we will grab the user's input and update our &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;city&lt;/code&gt; states, then call &lt;code&gt;doLogIn&lt;/code&gt; to start the mock request/delay.&lt;/li&gt;
&lt;li&gt;When the delay starts, we must hide our view and show the loading indicator.&lt;/li&gt;
&lt;li&gt;When the delay ends, we must hide the loading indicator and show our view. Then, we navigate to the landing screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Override &lt;code&gt;onViewCreated&lt;/code&gt; and implement the on-click listener as described:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LoginFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;loginButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="c1"&gt;// Update the state&lt;/span&gt;
            &lt;span class="n"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNameAndCity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;loginNameText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;loginCityText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doLogIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of &lt;a href="https://kotlinlang.org/docs/tutorials/android-plugin.html" rel="noopener noreferrer"&gt;Kotlin Android Extensions&lt;/a&gt;, we are able to directly reference the view without calling &lt;code&gt;findViewById&lt;/code&gt;. This is called View Binding (similar to getting a &lt;code&gt;ref&lt;/code&gt; to a node in React) .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: in the future, it will be recommended to use the &lt;a href="https://developer.android.com/topic/libraries/view-binding" rel="noopener noreferrer"&gt;View Binding component&lt;/a&gt; which has some advantages and none of the &lt;a href="https://old.reddit.com/r/androiddev/comments/ala9p2/why_kotlinx_synthetic_is_no_longer_a_recommended/efdvpkg/" rel="noopener noreferrer"&gt;drawbacks&lt;/a&gt;. It will be available in newer versions of Android Studio.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;doLogIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Single&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;just&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delaySubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Schedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidSchedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mainThread&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;MvRx makes use of RxJava. Primer: RxJava is very useful in Android development as it offers a neat API for handling asynchronous logic (Like JavaScript promises, but with more capabilities). &lt;/p&gt;

&lt;p&gt;It is important to execute long running tasks off the main thread (also called UI thread) to prevent the app from dropping frames. RxJava allows you to declaratively switch threads with ease. &lt;/p&gt;

&lt;p&gt;To use any of RxJava's APIs, we must work with the &lt;code&gt;observable&lt;/code&gt; type. RxJava has APIs to create observables from things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;doLogin()&lt;/code&gt; is called when the login button is pressed. Let's go through it in detail as Rx can be intimidating if you've never used it before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Single&lt;/code&gt; is a type of observable that resolves to a single value, exactly like a JavaScript promise.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;just()&lt;/code&gt; is used to denote that this observable resolves to just this item, in this case the item is &lt;code&gt;true&lt;/code&gt;. So the first line is equivalent to &lt;code&gt;Promise.resolve(true)&lt;/code&gt; in JavaScript.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delaySubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We need to subscribe to an observable to receive a result from it. This line states that any subscription should be delayed by 5 seconds.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Schedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AndroidSchedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mainThread&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here, we state that we wish to subscribe to this observable using an &lt;code&gt;io&lt;/code&gt; thread by the help of the &lt;code&gt;io&lt;/code&gt; scheduler and ask for value notifications to be sent to the main thread.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&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;ul&gt;
&lt;li&gt;
&lt;code&gt;execute&lt;/code&gt; is a neat helper function by MvRx that maps the current state of this process to our &lt;code&gt;loggedIn&lt;/code&gt; async type. When the observable is executed, &lt;code&gt;loggedIn&lt;/code&gt; type is updated to &lt;code&gt;Loading&lt;/code&gt;. When it is done, &lt;code&gt;loggedIn&lt;/code&gt; type and value are updated to &lt;code&gt;Success&lt;/code&gt; and &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, the &lt;code&gt;invalidate()&lt;/code&gt; function comes in handy. This function is called every time our state is updated (just like a React re-render). Here, we can make changes to our view according to the current state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LoginFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="o"&gt;..&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;withState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;loadingIndicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Loading&lt;/span&gt;
            &lt;span class="n"&gt;loginNameText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Loading&lt;/span&gt;
            &lt;span class="n"&gt;loginCityText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Loading&lt;/span&gt;
            &lt;span class="n"&gt;loginButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Loading&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loggedIn&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;findNavController&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action_loginFragment_to_landingFragment2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;withState&lt;/code&gt; allows us to access the current state of our view model. Inside, we map the loading state of &lt;code&gt;loggedIn&lt;/code&gt; to the visibility of our loading indicator, inputs and button. If &lt;code&gt;loggedIn&lt;/code&gt; is of type &lt;code&gt;Success&lt;/code&gt;, then we navigate to the landing screen. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.android.com/kotlin/ktx#navigation" rel="noopener noreferrer"&gt;Navigation KTX&lt;/a&gt; helps us obtain a reference to the navigation controller here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the landing fragment, we need to implement &lt;code&gt;invalidate()&lt;/code&gt; and update our texts using the current state. We will add a listener to our logout button that sets &lt;code&gt;loggedIn&lt;/code&gt; to &lt;code&gt;Uninitialized&lt;/code&gt; and then pops our fragment off of the navigation stack, going back to the login screen.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LandingFragment.kt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="o"&gt;..&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;logoutButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doLogout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;findNavController&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;popBackStack&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;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;withState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formViewModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;landingCityText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;
            &lt;span class="n"&gt;landingNameText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNuk7agr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNuk7agr.gif" alt="Mymvrxapp gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Courtesy of &lt;code&gt;logStateChanges()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D/FormViewModel: New State: FormState(name=Osama, city=Cyberjaya, loggedIn=com.airbnb.mvrx.Uninitialized@24591c4)
D/FormViewModel: New State: FormState(name=Osama, city=Cyberjaya, loggedIn=com.airbnb.mvrx.Loading@7749791c)
D/FormViewModel: New State: FormState(name=Osama, city=Cyberjaya, loggedIn=Success(value=true))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All done! Hope you've enjoyed this guide and found it useful.&lt;/p&gt;

&lt;p&gt;If you'd like to learn more about MvRx, I suggest going through their &lt;a href="https://github.com/airbnb/MvRx/wiki" rel="noopener noreferrer"&gt;wiki&lt;/a&gt; and code samples on their &lt;a href="https://github.com/airbnb/MvRx/" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>android</category>
      <category>kotlin</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>A Brief Intro to RxJs</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Sun, 25 Aug 2019 11:41:51 +0000</pubDate>
      <link>https://forem.com/osamaqarem/a-brief-intro-to-rxjs-egb</link>
      <guid>https://forem.com/osamaqarem/a-brief-intro-to-rxjs-egb</guid>
      <description>&lt;p&gt;This article was originally posted on my &lt;a href="https://osamaq.com/promises-to-rxjs-observables/"&gt;blog&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://rxjs.dev/"&gt;RxJs&lt;/a&gt; is the implementation of &lt;a href="http://reactivex.io/"&gt;Reactive Extensions&lt;/a&gt; for Javascript. These extensions are a collection of tools allowing us to write declarative reactive code as opposed to imperative (e.g. &lt;code&gt;do this when x&lt;/code&gt; instead of &lt;code&gt;if x is this right now, then do the following...&lt;/code&gt;). Basically, it gives us operators (functions) that can enhance handling of event-based logic, especially when working with multiple correlated events.&lt;/p&gt;

&lt;p&gt;Rx definitely has a learning curve. New concepts and and terms can be overwhelming at the start. But once you try enough times, eventually it clicks and you get much faster at learning the all the wizzabanga words and concepts. I'll try to keep this post as simple as possible, but you definitely need to be comfortable with the promises API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promises vs Observables
&lt;/h2&gt;

&lt;p&gt;Imagine we have an array of strings describing our thoughts.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thoughts&lt;/span&gt; &lt;span class="o"&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;food&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;sleep&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;code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Promise
&lt;/h3&gt;

&lt;p&gt;When we work with events in JavaScript we will typically uses the Promise API. For a promise, two things can happen:&lt;/p&gt;

&lt;p&gt;1- It resolves with a single value.&lt;br&gt;&lt;br&gt;
2- It rejects with a single value, usually an error message.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Both 1 and 2 signal the completion of a promise.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thoughtsPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thoughts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Observable
&lt;/h3&gt;

&lt;p&gt;An observable is a stream of data from which we can get notifications with values. We can get those notifications in three different scenarios:&lt;/p&gt;

&lt;p&gt;1- When there is a new value from the stream. &lt;br&gt;&lt;br&gt;
2- When an error occurs giving us the error value.&lt;br&gt;&lt;br&gt;
3- When the stream is complete.&lt;/p&gt;

&lt;p&gt;One difference is that observables can &lt;strong&gt;&lt;em&gt;resolve many times with new values&lt;/em&gt;&lt;/strong&gt;. For example, imagine you want to show a video on your app to the user. Would it be better to let the user download the entire video all at once, or to stream it little by little? Observables can help you stream your data.&lt;/p&gt;

&lt;p&gt;Let's create an observable.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;from&lt;/code&gt; operator can transform data such as arrays or promises into observables which are streams of data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The trailing $ sign is a naming convention for observables in JS&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thoughts$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thoughts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Data
&lt;/h3&gt;

&lt;p&gt;Back to our promise. What do you suppose happens when &lt;code&gt;thoughtsPromise&lt;/code&gt; resolves?&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;thoughtsArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;thoughtsPromise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thoughtsArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Output: ["food", "sleep", "code"]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// handle error&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;We got the array all at once. And what do you think happens when we start to listen for values, in other words &lt;code&gt;subscribe&lt;/code&gt; to our &lt;code&gt;thoughts$&lt;/code&gt; observable?&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="c1"&gt;// We subscribe to an observable to get values from it&lt;/span&gt;
&lt;span class="nx"&gt;thoughts$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//handle error,&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="c1"&gt;// handle completion,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;//    food&lt;/span&gt;
&lt;span class="c1"&gt;//    sleep&lt;/span&gt;
&lt;span class="c1"&gt;//    code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the values from the array one by one. A stream of data. Cool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/embed/sharp-wing-vfuqn?fontsize=14&amp;amp;expanddevtools=1"&gt;Play with this example (React)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Do I have to know Rx?
&lt;/h2&gt;

&lt;p&gt;Nope. But here are some use cases to consider:&lt;/p&gt;

&lt;p&gt;1- To keep code flat in JS if you can't use &lt;code&gt;async await&lt;/code&gt; for some reason.&lt;/p&gt;

&lt;p&gt;2- To handle complex event-based logic whether its network related or UI related (e.g. websockets / drag and drop).&lt;/p&gt;

&lt;p&gt;3- If your teammates come from different languages but you all know Rx, it might be easier for them to just get going with RxJs than to use &lt;code&gt;promises&lt;/code&gt; and &lt;code&gt;async await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;4- In other languages, Rx is super useful for handling multi-threading.&lt;/p&gt;

&lt;p&gt;5- If you enjoy reactive programming and want to apply it everywhere, go ahead 🙂.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/embed/pensive-resonance-z5qci?fontsize=14"&gt;Debouncing user input (React)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;List of Rx operators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://reactivex.io/documentation/operators.html"&gt;http://reactivex.io/documentation/operators.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Awesome video on RxJs operators by Fireship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ewcoEYS85Co"&gt;https://www.youtube.com/watch?v=ewcoEYS85Co&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reactive programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Reactive_programming"&gt;https://en.wikipedia.org/wiki/Reactive_programming&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Imperative programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Imperative_programming"&gt;https://en.wikipedia.org/wiki/Imperative_programming&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declarative programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Declarative_programming"&gt;https://en.wikipedia.org/wiki/Declarative_programming&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Observer Pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Observer_pattern"&gt;https://en.wikipedia.org/wiki/Observer_pattern&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>promises</category>
      <category>rxjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Chunking Arrays in Javascript</title>
      <dc:creator>Osama Qarem</dc:creator>
      <pubDate>Thu, 22 Aug 2019 01:34:56 +0000</pubDate>
      <link>https://forem.com/osamaqarem/chunking-arrays-in-javascript-164p</link>
      <guid>https://forem.com/osamaqarem/chunking-arrays-in-javascript-164p</guid>
      <description>&lt;p&gt;I recently ran into an issue inserting large data into an SQLite database on my react native app. I had purposely created a large mock data set to test what would happen should the user attempt something similar.&lt;/p&gt;

&lt;p&gt;And I instantly ran into an SQLite limit, specifically number 9.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.sqlite.org/limits.html"&gt;https://www.sqlite.org/limits.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;QueryFailedError:
too many SQL variables (code 1 SQLITE_ERROR):, while compiling:
INSERT INTO "table_name"("Id", "columnOne", "columnTwo") VALUES (...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apparently, this is to protect against excessive memory allocation. You can read more about it in the link above.&lt;/p&gt;

&lt;p&gt;The problematic query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeORM&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;largeArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we can do here is chunk our data. We can then run multiple queries instead of just one to insert the same amount of data.&lt;/p&gt;

&lt;p&gt;To illustrate the data that we currently have, I'll use an array of strings:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beforeChunking&lt;/span&gt; &lt;span class="o"&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;1&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;2&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;3&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;4&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;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we want to have is arrray of arrays with a specified chunk size. For example with a chunk size of &lt;code&gt;2&lt;/code&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;afterChunking&lt;/span&gt; &lt;span class="o"&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;1&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;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&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;4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can go about achieving this by utilizing &lt;code&gt;splice()&lt;/code&gt;. We create a function that takes in the data to chunk and the required chunk size.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getArrayAsChunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&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;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;while&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&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;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;splice()&lt;/code&gt; will remove elements from &lt;code&gt;data&lt;/code&gt; the size of &lt;code&gt;chunkSize&lt;/code&gt;. The remaining elements will move backwards in the array so everything works out.&lt;/p&gt;

&lt;p&gt;Now we can run our insert query(ies) like so:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunksArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getArrayAsChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;largeArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;chunksArray&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="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;oneChunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneChunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This took less than two seconds to insert ~2000 rows on a low-end android phone, so I left it at that. But one performance improvement we can make here is to define the SQL query ourselves, rather than let our ORM handle that; generating the query many times over incurs a cost.&lt;/p&gt;




&lt;p&gt;This article was originally posted on my &lt;a href="https://osamaq.com/chunking-arrays-in-javascript/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sqlite</category>
      <category>javascript</category>
      <category>typeorm</category>
      <category>array</category>
    </item>
  </channel>
</rss>
