<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Subrata Kumar Das</title>
    <description>The latest articles on DEV Community by Subrata Kumar Das (@subraatakumar).</description>
    <link>https://dev.to/subraatakumar</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1705863%2Fa3772c0b-286a-49ea-8edc-b23b70144507.png</url>
      <title>DEV Community: Subrata Kumar Das</title>
      <link>https://dev.to/subraatakumar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/subraatakumar"/>
    <language>en</language>
    <item>
      <title>Subra AI: Private Offline On-Device AI</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Fri, 24 Jul 2026 12:39:23 +0000</pubDate>
      <link>https://dev.to/subraatakumar/subra-ai-private-offline-on-device-ai-187m</link>
      <guid>https://dev.to/subraatakumar/subra-ai-private-offline-on-device-ai-187m</guid>
      <description></description>
    </item>
    <item>
      <title>Synchronous TurboModules Are Not Automatically Fast</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Wed, 15 Jul 2026 05:14:04 +0000</pubDate>
      <link>https://dev.to/subraatakumar/synchronous-turbomodules-are-not-automatically-fast-1fb6</link>
      <guid>https://dev.to/subraatakumar/synchronous-turbomodules-are-not-automatically-fast-1fb6</guid>
      <description>&lt;p&gt;React Native’s New Architecture gives JavaScript more direct access to native functionality.&lt;/p&gt;

&lt;p&gt;One important capability is synchronous communication through TurboModules.&lt;/p&gt;

&lt;p&gt;That can be useful.&lt;/p&gt;

&lt;p&gt;It can also introduce a performance problem that is easy to miss:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A native method being synchronous does not mean the native work is fast.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The communication mechanism may be efficient, but the JavaScript thread must still wait for the native operation to finish.&lt;/p&gt;

&lt;p&gt;That difference matters in production applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  The misleading simplicity of a synchronous API
&lt;/h2&gt;

&lt;p&gt;Consider a native method exposed 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SecureStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the JavaScript side, it looks harmless.&lt;/p&gt;

&lt;p&gt;There is no &lt;code&gt;await&lt;/code&gt;, no callback and no visible asynchronous workflow.&lt;/p&gt;

&lt;p&gt;The value is returned immediately from the developer’s point of view.&lt;/p&gt;

&lt;p&gt;But the native implementation may perform several operations before returning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;access Android Keystore or iOS Keychain&lt;/li&gt;
&lt;li&gt;decrypt stored data&lt;/li&gt;
&lt;li&gt;read from disk&lt;/li&gt;
&lt;li&gt;parse JSON&lt;/li&gt;
&lt;li&gt;convert native objects into JavaScript-compatible values&lt;/li&gt;
&lt;li&gt;communicate with another system service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this work takes time, JavaScript cannot continue until the method returns.&lt;/p&gt;

&lt;p&gt;The API looks simple.&lt;/p&gt;

&lt;p&gt;The execution may not be.&lt;/p&gt;




&lt;h2&gt;
  
  
  What synchronous actually means
&lt;/h2&gt;

&lt;p&gt;A synchronous call means the caller waits for the result.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NativeModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;renderScreen&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;renderScreen&lt;/code&gt; cannot begin until &lt;code&gt;getValue()&lt;/code&gt; finishes.&lt;/p&gt;

&lt;p&gt;That behaviour is acceptable when the native operation is extremely small and predictable.&lt;/p&gt;

&lt;p&gt;It becomes dangerous when the operation has variable latency.&lt;/p&gt;

&lt;p&gt;The same method may take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less than one millisecond when data is cached&lt;/li&gt;
&lt;li&gt;several milliseconds when data requires conversion&lt;/li&gt;
&lt;li&gt;much longer when storage, cryptography or system services are involved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The JavaScript thread does not care why the native method is delayed.&lt;/p&gt;

&lt;p&gt;It simply remains blocked.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this affects React Native performance
&lt;/h2&gt;

&lt;p&gt;React Native applications perform important work on the JavaScript thread.&lt;/p&gt;

&lt;p&gt;This can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;processing state updates&lt;/li&gt;
&lt;li&gt;running application logic&lt;/li&gt;
&lt;li&gt;handling user interactions&lt;/li&gt;
&lt;li&gt;preparing React renders&lt;/li&gt;
&lt;li&gt;coordinating navigation&lt;/li&gt;
&lt;li&gt;executing animation-related JavaScript&lt;/li&gt;
&lt;li&gt;responding to events from native modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a synchronous native method blocks that thread, other JavaScript work must wait.&lt;/p&gt;

&lt;p&gt;A single call may not create an obvious problem.&lt;/p&gt;

&lt;p&gt;Repeated calls can.&lt;/p&gt;

&lt;p&gt;Imagine that a component reads a secure value during rendering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AccountScreen&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SecureStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AccountDetails&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine that the component renders multiple times during navigation or state updates.&lt;/p&gt;

&lt;p&gt;Every render may trigger another native operation.&lt;/p&gt;

&lt;p&gt;If the method accesses storage and performs decryption, the application is repeatedly blocking the JavaScript thread inside the render path.&lt;/p&gt;

&lt;p&gt;The visible result may be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;slow navigation&lt;/li&gt;
&lt;li&gt;delayed button responses&lt;/li&gt;
&lt;li&gt;dropped animation frames&lt;/li&gt;
&lt;li&gt;inconsistent screen transitions&lt;/li&gt;
&lt;li&gt;temporary UI freezes&lt;/li&gt;
&lt;li&gt;performance that becomes worse on lower-end devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The developer may initially investigate React re-renders.&lt;/p&gt;

&lt;p&gt;The real problem is the synchronous native work performed during those renders.&lt;/p&gt;




&lt;h2&gt;
  
  
  TurboModules reduce overhead, not execution cost
&lt;/h2&gt;

&lt;p&gt;This is the central distinction.&lt;/p&gt;

&lt;p&gt;TurboModules improve how JavaScript and native code communicate.&lt;/p&gt;

&lt;p&gt;They can reduce some of the overhead associated with the older bridge architecture.&lt;/p&gt;

&lt;p&gt;But TurboModules do not make the native operation itself free.&lt;/p&gt;

&lt;p&gt;Suppose a native method performs three tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read secure storage
        ↓
Decrypt the value
        ↓
Convert it into a JavaScript object
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The communication layer may be efficient.&lt;/p&gt;

&lt;p&gt;The application must still pay for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;storage access&lt;/li&gt;
&lt;li&gt;cryptographic processing&lt;/li&gt;
&lt;li&gt;object allocation&lt;/li&gt;
&lt;li&gt;data conversion&lt;/li&gt;
&lt;li&gt;thread coordination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optimising the path between JavaScript and native code does not eliminate the work happening at the destination.&lt;/p&gt;

&lt;p&gt;A faster doorway does not make the room behind it smaller.&lt;/p&gt;




&lt;h2&gt;
  
  
  When synchronous native methods are appropriate
&lt;/h2&gt;

&lt;p&gt;Synchronous methods are useful when the operation is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tiny&lt;/li&gt;
&lt;li&gt;deterministic&lt;/li&gt;
&lt;li&gt;memory-resident&lt;/li&gt;
&lt;li&gt;frequently required&lt;/li&gt;
&lt;li&gt;guaranteed not to perform slow I/O&lt;/li&gt;
&lt;li&gt;predictable across supported devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples may include reading a cached capability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supportsBiometrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DeviceCapabilities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasBiometricHardware&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or checking a native constant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AppConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEnvironment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or performing a very small calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DisplayUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dpToPixels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These operations are generally suitable only when their native implementation remains lightweight.&lt;/p&gt;

&lt;p&gt;The important question is not whether the return type is small.&lt;/p&gt;

&lt;p&gt;The important question is how the value is produced.&lt;/p&gt;

&lt;p&gt;Returning one boolean can still be expensive if the implementation queries a system service every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Operations that should usually remain asynchronous
&lt;/h2&gt;

&lt;p&gt;Native methods should normally be asynchronous when they involve:&lt;/p&gt;

&lt;h3&gt;
  
  
  Storage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profile&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;SecureStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProfile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disk and secure-storage access may have unpredictable latency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cryptography
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decryptedPayload&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;CryptoModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cryptographic work can become expensive depending on the algorithm and input size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NativeNetworkClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchConfiguration&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Network operations are naturally unpredictable and should never block JavaScript synchronously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Large data conversion
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;records&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;NativeDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRecords&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Converting thousands of native records into JavaScript objects can consume considerable time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image and file processing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;ImageProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Media processing is computationally expensive and should normally run away from latency-sensitive application work.&lt;/p&gt;

&lt;h3&gt;
  
  
  System services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&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;LocationModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response time may depend on permissions, sensors, device state and operating-system behaviour.&lt;/p&gt;




&lt;h2&gt;
  
  
  Avoid synchronous work inside rendering
&lt;/h2&gt;

&lt;p&gt;One of the strongest review rules is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not perform synchronous native work inside a React render path unless the operation is proven to be trivial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is risky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&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;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NativeSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSettings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DashboardContent&lt;/span&gt; &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better design is to load the value asynchronously and store it in application state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSettings&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Settings&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadSettings&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;value&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;NativeSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSettings&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;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setSettings&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;loadSettings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LoadingScreen&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DashboardContent&lt;/span&gt; &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact state-management approach may differ.&lt;/p&gt;

&lt;p&gt;The principle remains the same:&lt;/p&gt;

&lt;p&gt;Do not make rendering wait for native storage, cryptography or system resources.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cache deliberately, not accidentally
&lt;/h2&gt;

&lt;p&gt;Sometimes a synchronous API is created because the application needs immediate access to a value.&lt;/p&gt;

&lt;p&gt;The safer solution may be to load the value earlier and maintain an in-memory cache.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SessionStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;initialise&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&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;SecureStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getCachedToken&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&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;The native storage operation remains asynchronous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sessionStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later reads are synchronous because they access application memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCachedToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a meaningful distinction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;loading from storage is asynchronous&lt;/li&gt;
&lt;li&gt;reading an already-loaded value is synchronous&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is much safer than hiding storage access behind a synchronous API.&lt;/p&gt;

&lt;p&gt;However, caching introduces its own responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cache invalidation&lt;/li&gt;
&lt;li&gt;logout handling&lt;/li&gt;
&lt;li&gt;token refresh&lt;/li&gt;
&lt;li&gt;memory lifecycle&lt;/li&gt;
&lt;li&gt;multi-process consistency&lt;/li&gt;
&lt;li&gt;protection of sensitive values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to make everything synchronous.&lt;/p&gt;

&lt;p&gt;The goal is to place expensive work outside latency-sensitive paths.&lt;/p&gt;




&lt;h2&gt;
  
  
  Measure the whole native method
&lt;/h2&gt;

&lt;p&gt;A common performance mistake is to measure only JavaScript execution.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SecureStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Completed in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can reveal blocking time from the JavaScript side.&lt;/p&gt;

&lt;p&gt;But deeper investigation may require native instrumentation.&lt;/p&gt;

&lt;p&gt;On Android, developers can measure sections using native timing tools or platform profilers.&lt;/p&gt;

&lt;p&gt;On iOS, Instruments can help identify time spent in storage, cryptography, object conversion and thread blocking.&lt;/p&gt;

&lt;p&gt;The useful questions are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How long does the method take on average?&lt;/li&gt;
&lt;li&gt;What is the worst observed latency?&lt;/li&gt;
&lt;li&gt;Does the duration change when the value is not cached?&lt;/li&gt;
&lt;li&gt;Does the method perform disk access?&lt;/li&gt;
&lt;li&gt;Does it allocate or convert large objects?&lt;/li&gt;
&lt;li&gt;Is it called during rendering or navigation?&lt;/li&gt;
&lt;li&gt;How many times is it called during one user action?&lt;/li&gt;
&lt;li&gt;How does it behave on lower-end devices?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Average timing alone is not enough.&lt;/p&gt;

&lt;p&gt;A method that normally completes quickly but occasionally blocks for 40 milliseconds can still create visible UI problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Watch for repeated synchronous calls
&lt;/h2&gt;

&lt;p&gt;The cost of one method call may appear acceptable.&lt;/p&gt;

&lt;p&gt;The call frequency may be the actual problem.&lt;/p&gt;

&lt;p&gt;Consider:&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="nx"&gt;items&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;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;NativeFormatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are 500 items, the application performs 500 synchronous native calls.&lt;/p&gt;

&lt;p&gt;Even if each call takes only a fraction of a millisecond, the combined cost can become significant.&lt;/p&gt;

&lt;p&gt;A stronger native API might process the entire collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formattedItems&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;NativeFormatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can reduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repeated boundary crossings&lt;/li&gt;
&lt;li&gt;repeated allocations&lt;/li&gt;
&lt;li&gt;thread coordination&lt;/li&gt;
&lt;li&gt;per-call conversion overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Batching is especially useful when working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database rows&lt;/li&gt;
&lt;li&gt;image metadata&lt;/li&gt;
&lt;li&gt;sensor records&lt;/li&gt;
&lt;li&gt;BLE data&lt;/li&gt;
&lt;li&gt;file lists&lt;/li&gt;
&lt;li&gt;cryptographic operations&lt;/li&gt;
&lt;li&gt;large arrays produced by native SDKs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The correct API shape often matters as much as the implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Synchronous methods create architectural coupling
&lt;/h2&gt;

&lt;p&gt;There is another risk beyond immediate performance.&lt;/p&gt;

&lt;p&gt;A synchronous API can become slow later.&lt;/p&gt;

&lt;p&gt;Version one may return an in-memory value:&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="nf"&gt;getUserRegion&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A future requirement may change the implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read the region from encrypted storage&lt;/li&gt;
&lt;li&gt;migrate an old value&lt;/li&gt;
&lt;li&gt;consult remote configuration&lt;/li&gt;
&lt;li&gt;query a native SDK&lt;/li&gt;
&lt;li&gt;support multiple user profiles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The JavaScript interface remains synchronous, but the native responsibility has become heavier.&lt;/p&gt;

&lt;p&gt;Now the team faces a difficult choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep blocking JavaScript&lt;/li&gt;
&lt;li&gt;introduce hidden caching&lt;/li&gt;
&lt;li&gt;change the public API&lt;/li&gt;
&lt;li&gt;maintain both synchronous and asynchronous versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For values likely to require I/O in the future, starting with an asynchronous contract is often safer.&lt;/p&gt;

&lt;p&gt;API design should consider how the operation may evolve, not only how it works today.&lt;/p&gt;




&lt;h2&gt;
  
  
  A practical decision rule
&lt;/h2&gt;

&lt;p&gt;Before exposing a synchronous TurboModule method, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can this method always complete quickly without storage, networking, cryptography, large conversion or unpredictable system work?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is uncertain, use an asynchronous API.&lt;/p&gt;

&lt;p&gt;A useful classification is:&lt;/p&gt;

&lt;h3&gt;
  
  
  Suitable for synchronous execution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;constants&lt;/li&gt;
&lt;li&gt;cached primitives&lt;/li&gt;
&lt;li&gt;tiny calculations&lt;/li&gt;
&lt;li&gt;in-memory flags&lt;/li&gt;
&lt;li&gt;deterministic capability checks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Better suited for asynchronous execution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;file access&lt;/li&gt;
&lt;li&gt;secure storage&lt;/li&gt;
&lt;li&gt;databases&lt;/li&gt;
&lt;li&gt;networking&lt;/li&gt;
&lt;li&gt;encryption and decryption&lt;/li&gt;
&lt;li&gt;compression&lt;/li&gt;
&lt;li&gt;image processing&lt;/li&gt;
&lt;li&gt;large data conversion&lt;/li&gt;
&lt;li&gt;hardware interaction&lt;/li&gt;
&lt;li&gt;operating-system services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The method’s name is not enough.&lt;/p&gt;

&lt;p&gt;Review the complete native execution path.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code-review checklist
&lt;/h2&gt;

&lt;p&gt;When reviewing a synchronous TurboModule method, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it perform disk or secure-storage access?&lt;/li&gt;
&lt;li&gt;Does it call another SDK or system service?&lt;/li&gt;
&lt;li&gt;Does it perform cryptography?&lt;/li&gt;
&lt;li&gt;Can it return a large object or array?&lt;/li&gt;
&lt;li&gt;Does it parse or serialise data?&lt;/li&gt;
&lt;li&gt;Can its latency change based on device state?&lt;/li&gt;
&lt;li&gt;Is it called during rendering?&lt;/li&gt;
&lt;li&gt;Is it called repeatedly inside a loop?&lt;/li&gt;
&lt;li&gt;Is the result already available in memory?&lt;/li&gt;
&lt;li&gt;Could the method become more expensive later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One concerning answer may be enough to reconsider the synchronous design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;TurboModules can improve React Native’s native integration model.&lt;/p&gt;

&lt;p&gt;They make direct and synchronous interactions possible where appropriate.&lt;/p&gt;

&lt;p&gt;But capability should not become default behaviour.&lt;/p&gt;

&lt;p&gt;The safest rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use synchronous native methods only for tiny, predictable and memory-resident operations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep storage, cryptography, networking, large data processing and unpredictable system work asynchronous.&lt;/p&gt;

&lt;p&gt;TurboModules reduce communication overhead.&lt;/p&gt;

&lt;p&gt;They do not remove the cost of native execution.&lt;/p&gt;

&lt;p&gt;Where have you seen a synchronous native method create unexpected UI latency in a React Native application?&lt;/p&gt;




</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>ai</category>
    </item>
    <item>
      <title>Type Safety Stops at Runtime Boundaries in React Native</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Mon, 13 Jul 2026 14:31:13 +0000</pubDate>
      <link>https://dev.to/subraatakumar/type-safety-stops-at-runtime-boundaries-in-react-native-ian</link>
      <guid>https://dev.to/subraatakumar/type-safety-stops-at-runtime-boundaries-in-react-native-ian</guid>
      <description>&lt;p&gt;TypeScript can make a React Native codebase safer.&lt;/p&gt;

&lt;p&gt;It can catch missing properties, incorrect function arguments, invalid component props and many other mistakes before the application runs.&lt;/p&gt;

&lt;p&gt;But TypeScript has one important limitation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It cannot verify whether external data actually matches the type you assigned to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This becomes especially important in React Native because application data often crosses multiple runtime boundaries.&lt;/p&gt;

&lt;p&gt;A value may come from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a native Android module&lt;/li&gt;
&lt;li&gt;an iOS native module&lt;/li&gt;
&lt;li&gt;an API response&lt;/li&gt;
&lt;li&gt;persisted storage&lt;/li&gt;
&lt;li&gt;a deep link&lt;/li&gt;
&lt;li&gt;remote configuration&lt;/li&gt;
&lt;li&gt;an analytics SDK&lt;/li&gt;
&lt;li&gt;an AI-generated JSON response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At each of these boundaries, the actual runtime value may differ from the TypeScript definition.&lt;/p&gt;

&lt;p&gt;And TypeScript may not warn you.&lt;/p&gt;




&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;Assume a React Native application receives battery information from a native module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;The JavaScript layer expects a value 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batteryStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks safe.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;level&lt;/code&gt; field is a number.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;isCharging&lt;/code&gt; field is a boolean.&lt;/p&gt;

&lt;p&gt;Now imagine that the Android implementation changes and returns this instead:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;82&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;level&lt;/code&gt; value is now a string.&lt;/p&gt;

&lt;p&gt;At runtime, JavaScript receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;batteryStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&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;But TypeScript may still believe that &lt;code&gt;level&lt;/code&gt; is a number.&lt;/p&gt;

&lt;p&gt;How can that happen?&lt;/p&gt;

&lt;p&gt;Because the result may have been cast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batteryStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;NativeModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BatteryModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cast tells TypeScript:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Trust me. This value is a &lt;code&gt;BatteryStatus&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TypeScript accepts that instruction.&lt;/p&gt;

&lt;p&gt;It does not inspect the Android or iOS runtime value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Casting is not validation
&lt;/h2&gt;

&lt;p&gt;This distinction is important.&lt;/p&gt;

&lt;p&gt;A type cast changes what TypeScript believes.&lt;/p&gt;

&lt;p&gt;It does not change or verify the actual value.&lt;/p&gt;

&lt;p&gt;Consider this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;82&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript may allow the code.&lt;/p&gt;

&lt;p&gt;But the runtime value is still a string.&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="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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why the following assumption is dangerous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;externalValue&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ExpectedType&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 may compile successfully while the application remains unsafe.&lt;/p&gt;

&lt;p&gt;A better mental model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Casting changes the compiler's understanding. Validation checks reality.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where the failure appears
&lt;/h2&gt;

&lt;p&gt;Boundary problems do not always fail immediately.&lt;/p&gt;

&lt;p&gt;That is one reason they can be difficult to diagnose.&lt;/p&gt;

&lt;p&gt;The application may receive the incorrect value on one screen, store it in state and fail much later.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextLevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;batteryStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;level&lt;/code&gt; is a number:&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="mi"&gt;82&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 92&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;level&lt;/code&gt; is a string:&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;82&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// "8210"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app may not crash.&lt;/p&gt;

&lt;p&gt;It may simply produce the wrong result.&lt;/p&gt;

&lt;p&gt;That is often worse because the problem can remain hidden.&lt;/p&gt;

&lt;p&gt;The value may also fail during:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;numeric comparisons&lt;/li&gt;
&lt;li&gt;sorting&lt;/li&gt;
&lt;li&gt;formatting&lt;/li&gt;
&lt;li&gt;progress calculations&lt;/li&gt;
&lt;li&gt;conditional rendering&lt;/li&gt;
&lt;li&gt;database queries&lt;/li&gt;
&lt;li&gt;analytics processing&lt;/li&gt;
&lt;li&gt;business-rule evaluation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;batteryStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;showLowBatteryWarning&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;JavaScript may coerce the value and produce a result.&lt;/p&gt;

&lt;p&gt;But relying on implicit coercion makes application behaviour fragile.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compile-time trust should stop at runtime boundaries
&lt;/h2&gt;

&lt;p&gt;Inside a properly typed TypeScript system, values can usually be trusted.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;showBatteryStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If every caller passes a real &lt;code&gt;BatteryStatus&lt;/code&gt;, the function is safe.&lt;/p&gt;

&lt;p&gt;The problem begins when a value enters the system from outside.&lt;/p&gt;

&lt;p&gt;That value has not been created or verified by TypeScript.&lt;/p&gt;

&lt;p&gt;Therefore, the safer rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Treat external values as &lt;code&gt;unknown&lt;/code&gt; until they have been validated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;NativeModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BatteryModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NativeModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BatteryModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the application is forced to prove that the value is safe before using it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why &lt;code&gt;unknown&lt;/code&gt; is better than &lt;code&gt;any&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Many boundary values are typed as &lt;code&gt;any&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchBatteryStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes most type protection.&lt;/p&gt;

&lt;p&gt;You can access anything:&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidProperty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anythingAtAll&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript will not stop you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;unknown&lt;/code&gt; behaves differently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchBatteryStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You cannot safely access its properties until you narrow the 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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// TypeScript error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may initially feel inconvenient.&lt;/p&gt;

&lt;p&gt;But that inconvenience is useful.&lt;/p&gt;

&lt;p&gt;It forces the code to validate the runtime value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Manual runtime validation
&lt;/h2&gt;

&lt;p&gt;A simple type guard can validate the native response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isBatteryStatus&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;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isCharging&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the boundary can be handled safely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NativeModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BatteryModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&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="nf"&gt;isBatteryStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawStatus&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid battery status returned by native module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the validation succeeds, TypeScript knows that &lt;code&gt;rawStatus&lt;/code&gt; is a valid &lt;code&gt;BatteryStatus&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a safe conversion from an untrusted value into a trusted application type.&lt;/p&gt;




&lt;h2&gt;
  
  
  Validate business rules, not only field types
&lt;/h2&gt;

&lt;p&gt;Checking whether &lt;code&gt;level&lt;/code&gt; is a number may not be enough.&lt;/p&gt;

&lt;p&gt;The value may still be invalid.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shape is correct.&lt;/p&gt;

&lt;p&gt;But a battery percentage of &lt;code&gt;400&lt;/code&gt; is not valid.&lt;/p&gt;

&lt;p&gt;A stronger validator should also verify allowed ranges.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isBatteryStatus&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;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isCharging&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runtime validation may need to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;required fields&lt;/li&gt;
&lt;li&gt;primitive types&lt;/li&gt;
&lt;li&gt;allowed ranges&lt;/li&gt;
&lt;li&gt;enum values&lt;/li&gt;
&lt;li&gt;string formats&lt;/li&gt;
&lt;li&gt;nested object shapes&lt;/li&gt;
&lt;li&gt;array item types&lt;/li&gt;
&lt;li&gt;mutually exclusive states&lt;/li&gt;
&lt;li&gt;domain-specific rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A structurally correct object can still be invalid for the application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Using a schema validation library
&lt;/h2&gt;

&lt;p&gt;Manual validation works well for small objects.&lt;/p&gt;

&lt;p&gt;For larger payloads, a schema library can make the code easier to maintain.&lt;/p&gt;

&lt;p&gt;A common approach is to define a schema and derive the TypeScript type from it.&lt;/p&gt;

&lt;p&gt;For example, using Zod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod&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;BatteryStatusSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&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="nf"&gt;max&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="na"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatusSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The external value can then be parsed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NativeModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BatteryModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatusSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawStatus&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid battery status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&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;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is not the specific library.&lt;/p&gt;

&lt;p&gt;The important part is the boundary discipline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive untrusted data.&lt;/li&gt;
&lt;li&gt;Validate it.&lt;/li&gt;
&lt;li&gt;Convert it into a trusted type.&lt;/li&gt;
&lt;li&gt;Use it inside the application.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Runtime boundaries in React Native
&lt;/h2&gt;

&lt;p&gt;React Native applications contain more boundaries than many teams realise.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Native modules
&lt;/h3&gt;

&lt;p&gt;Native modules may return different types across Android and iOS.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android returns an integer&lt;/li&gt;
&lt;li&gt;iOS returns a floating-point number&lt;/li&gt;
&lt;li&gt;one platform returns &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the other platform omits the field&lt;/li&gt;
&lt;li&gt;a native SDK returns a string representation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generated TurboModule specifications can improve contract safety, but runtime validation may still be useful when data originates from external native SDKs, persisted native state or platform APIs.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Network responses
&lt;/h3&gt;

&lt;p&gt;An API client may declare a generic response 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not guarantee that the server returned a valid &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It only tells TypeScript how the code intends to use the response.&lt;/p&gt;

&lt;p&gt;The backend may return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"42"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while the application expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;API types are expectations until runtime validation confirms them.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Persisted storage
&lt;/h3&gt;

&lt;p&gt;Data stored in AsyncStorage, MMKV, SQLite or another persistence layer can become stale.&lt;/p&gt;

&lt;p&gt;The application model may change between releases.&lt;/p&gt;

&lt;p&gt;An older app version may have saved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dark"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A newer version may expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;fontScale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading stored JSON and casting it directly can create hidden problems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storedValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parsing confirms only that the value is valid JSON.&lt;/p&gt;

&lt;p&gt;It does not confirm that it matches &lt;code&gt;Settings&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Deep links
&lt;/h3&gt;

&lt;p&gt;Deep-link parameters are external input.&lt;/p&gt;

&lt;p&gt;A link may contain missing, malformed or unexpected values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myapp://payment?amount=abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application should not assume that &lt;code&gt;amount&lt;/code&gt; is a valid number merely because the navigation type expects one.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Remote configuration
&lt;/h3&gt;

&lt;p&gt;Remote configuration can change without an application release.&lt;/p&gt;

&lt;p&gt;A field that was previously boolean may accidentally be configured as a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newCheckoutEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without validation, the application may treat a non-empty string as truthy and enable behaviour unexpectedly.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. AI-generated structured output
&lt;/h3&gt;

&lt;p&gt;AI-generated JSON should always be treated as untrusted.&lt;/p&gt;

&lt;p&gt;Even when a model is instructed to follow a specific schema, it may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;omit required fields&lt;/li&gt;
&lt;li&gt;return additional fields&lt;/li&gt;
&lt;li&gt;use incorrect enum values&lt;/li&gt;
&lt;li&gt;produce malformed JSON&lt;/li&gt;
&lt;li&gt;return numbers as strings&lt;/li&gt;
&lt;li&gt;generate semantically invalid combinations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extremely_urgent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"retryCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-3"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response may look structured while still violating the application contract.&lt;/p&gt;

&lt;p&gt;AI output requires both structural validation and business-rule validation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Validate once at the edge
&lt;/h2&gt;

&lt;p&gt;Runtime validation should not be scattered throughout the entire application.&lt;/p&gt;

&lt;p&gt;That creates repetitive and inconsistent checks.&lt;/p&gt;

&lt;p&gt;A stronger architecture validates values at the edge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBatteryStatus&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BatteryStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;rawStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NativeModules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BatteryModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStatus&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;BatteryStatusSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawStatus&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;The rest of the application can now depend on the trusted function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getBatteryStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;renderBatteryLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the codebase a clear separation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Untrusted external data
        ↓
Boundary validation
        ↓
Trusted application model
        ↓
Business logic and UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The validation cost is paid once.&lt;/p&gt;

&lt;p&gt;The trusted type can then flow safely through the internal system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Parse, do not merely check
&lt;/h2&gt;

&lt;p&gt;In some cases, the application may intentionally transform external data.&lt;/p&gt;

&lt;p&gt;Suppose the native module returns:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;82&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application may decide that numeric strings are acceptable.&lt;/p&gt;

&lt;p&gt;Instead of rejecting the value, the boundary parser can normalise it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseBatteryStatus&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;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;BatteryStatus&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Battery status must be an object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid battery level&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isCharging&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid charging state&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isCharging&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;This approach is often called parsing rather than validation.&lt;/p&gt;

&lt;p&gt;Validation asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this value already valid?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Parsing asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can this value be safely converted into the trusted form?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both approaches are useful.&lt;/p&gt;

&lt;p&gt;The choice should be explicit.&lt;/p&gt;




&lt;h2&gt;
  
  
  A practical code-review checklist
&lt;/h2&gt;

&lt;p&gt;Whenever a value enters a React Native application, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where did this value come from?&lt;/li&gt;
&lt;li&gt;Is the source controlled by the TypeScript compiler?&lt;/li&gt;
&lt;li&gt;Is the value typed as &lt;code&gt;any&lt;/code&gt; or cast using &lt;code&gt;as&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;What happens if a field is missing?&lt;/li&gt;
&lt;li&gt;What happens if a number arrives as a string?&lt;/li&gt;
&lt;li&gt;Are null and undefined handled differently?&lt;/li&gt;
&lt;li&gt;Are allowed ranges and enum values checked?&lt;/li&gt;
&lt;li&gt;Is validation performed once at the boundary?&lt;/li&gt;
&lt;li&gt;Is the failure logged with enough context?&lt;/li&gt;
&lt;li&gt;Can the application recover safely from invalid data?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These questions are especially important during:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native-module reviews&lt;/li&gt;
&lt;li&gt;API integration&lt;/li&gt;
&lt;li&gt;storage migrations&lt;/li&gt;
&lt;li&gt;SDK upgrades&lt;/li&gt;
&lt;li&gt;backend contract changes&lt;/li&gt;
&lt;li&gt;AI feature development&lt;/li&gt;
&lt;li&gt;platform-specific debugging&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;TypeScript is excellent at preserving correctness inside a typed system.&lt;/p&gt;

&lt;p&gt;But it does not control the values coming from outside that system.&lt;/p&gt;

&lt;p&gt;A type definition describes what the application expects.&lt;/p&gt;

&lt;p&gt;A type cast tells the compiler what to believe.&lt;/p&gt;

&lt;p&gt;Runtime validation checks what the application actually received.&lt;/p&gt;

&lt;p&gt;The engineering rule is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Treat external values as &lt;code&gt;unknown&lt;/code&gt;, validate them at the boundary and only then convert them into trusted application types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because in production React Native applications:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Casting is not validation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Which runtime boundary has caused the most unexpected type failure in your React Native application?&lt;/p&gt;




</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Your Offline-First App Can Lose Correct Data Without Showing Any Error</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Sun, 12 Jul 2026 07:07:30 +0000</pubDate>
      <link>https://dev.to/subraatakumar/your-offline-first-app-can-lose-correct-data-without-showing-any-error-1bm4</link>
      <guid>https://dev.to/subraatakumar/your-offline-first-app-can-lose-correct-data-without-showing-any-error-1bm4</guid>
      <description>&lt;p&gt;An offline-first application can complete synchronization successfully and still produce the wrong result.&lt;/p&gt;

&lt;p&gt;The API may return &lt;code&gt;200 OK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The local mutation queue may become empty.&lt;/p&gt;

&lt;p&gt;The device may show that all changes are synchronized.&lt;/p&gt;

&lt;p&gt;And yet, one valid update may have silently overwritten another.&lt;/p&gt;

&lt;p&gt;This is one of the most dangerous offline-first failures because nothing appears broken technically.&lt;/p&gt;

&lt;p&gt;There is no crash.&lt;/p&gt;

&lt;p&gt;There is no network error.&lt;/p&gt;

&lt;p&gt;There is no failed request.&lt;/p&gt;

&lt;p&gt;The system behaves exactly as implemented.&lt;/p&gt;

&lt;p&gt;The problem is that the implementation never defined which version of the data should win.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Failure Scenario
&lt;/h2&gt;

&lt;p&gt;Consider a maintenance application used by field technicians and supervisors.&lt;/p&gt;

&lt;p&gt;A technician opens a maintenance request while working in an area with poor connectivity.&lt;/p&gt;

&lt;p&gt;The current request contains:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REQ-1042&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPEN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MEDIUM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Initial inspection pending&lt;/span&gt;&lt;span class="dl"&gt;"&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="mi"&gt;4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The technician goes offline and updates the request:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IN_PROGRESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inspection started at the site&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;Before the technician reconnects, a supervisor opens the same request through a web dashboard and changes the priority:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HIGH&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Potential safety risk reported&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;Now two valid versions exist.&lt;/p&gt;

&lt;p&gt;The technician’s device contains one valid update.&lt;/p&gt;

&lt;p&gt;The server contains another valid update.&lt;/p&gt;

&lt;p&gt;When the device reconnects, the mobile application sends its pending mutation.&lt;/p&gt;

&lt;p&gt;The difficult question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we upload the local data?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difficult question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which version should be trusted?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Last-Write-Wins Is Not Always Conflict Resolution
&lt;/h2&gt;

&lt;p&gt;A common implementation compares timestamps and keeps the latest update.&lt;/p&gt;

&lt;p&gt;This is known as last-write-wins.&lt;/p&gt;

&lt;p&gt;For some fields, this may be acceptable.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a profile description&lt;/li&gt;
&lt;li&gt;a temporary draft&lt;/li&gt;
&lt;li&gt;a non-critical display preference&lt;/li&gt;
&lt;li&gt;an editable note where losing an earlier version is acceptable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But last-write-wins becomes dangerous when the conflicting data includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;approval status&lt;/li&gt;
&lt;li&gt;inspection findings&lt;/li&gt;
&lt;li&gt;financial values&lt;/li&gt;
&lt;li&gt;compliance records&lt;/li&gt;
&lt;li&gt;safety-related decisions&lt;/li&gt;
&lt;li&gt;healthcare information&lt;/li&gt;
&lt;li&gt;task ownership&lt;/li&gt;
&lt;li&gt;inventory quantities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine that the technician’s update is submitted five seconds after the supervisor’s update.&lt;/p&gt;

&lt;p&gt;A timestamp-based strategy may replace the supervisor’s high-priority safety warning with the technician’s older local copy.&lt;/p&gt;

&lt;p&gt;The synchronization request succeeds.&lt;/p&gt;

&lt;p&gt;The server accepts the payload.&lt;/p&gt;

&lt;p&gt;The local queue is cleared.&lt;/p&gt;

&lt;p&gt;But an important update has been lost.&lt;/p&gt;

&lt;p&gt;That is not a networking failure.&lt;/p&gt;

&lt;p&gt;It is an architecture failure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Offline-First Is a Business-Rules Problem
&lt;/h2&gt;

&lt;p&gt;Offline-first architecture is often described using technical components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite or Realm&lt;/li&gt;
&lt;li&gt;local persistence&lt;/li&gt;
&lt;li&gt;mutation queues&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;background synchronization&lt;/li&gt;
&lt;li&gt;connectivity listeners&lt;/li&gt;
&lt;li&gt;optimistic UI updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These components are important.&lt;/p&gt;

&lt;p&gt;But they only solve the mechanics of storing and transporting data.&lt;/p&gt;

&lt;p&gt;They do not decide what should happen when two correct versions disagree.&lt;/p&gt;

&lt;p&gt;That decision belongs to business rules.&lt;/p&gt;

&lt;p&gt;Before building the synchronization engine, every important field or operation should have a conflict-resolution policy.&lt;/p&gt;

&lt;p&gt;A useful starting point is to define four possible outcomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Merge&lt;/li&gt;
&lt;li&gt;Reject&lt;/li&gt;
&lt;li&gt;Overwrite&lt;/li&gt;
&lt;li&gt;Review&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Merge
&lt;/h2&gt;

&lt;p&gt;Use merging when both updates can safely coexist.&lt;/p&gt;

&lt;p&gt;Suppose the server contains:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tags&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;electrical&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The offline device adds:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tags&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;urgent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of replacing one array with the other, the system can merge them:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tags&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;electrical&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;urgent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Append-only activity logs are another good candidate for merging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActivityEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;requestId&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;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;createdAt&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;createdBy&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each action becomes a separate immutable event.&lt;/p&gt;

&lt;p&gt;The system adds new events instead of replacing the complete history.&lt;/p&gt;

&lt;p&gt;This makes synchronization safer because concurrent actions do not compete for ownership of the same record.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Reject
&lt;/h2&gt;

&lt;p&gt;Some fields should be controlled only by the server.&lt;/p&gt;

&lt;p&gt;For example:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;approvedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manager-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;approvedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-07-12T10:30:00Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;complianceStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VERIFIED&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;A mobile device should not be allowed to overwrite these values from an old local snapshot.&lt;/p&gt;

&lt;p&gt;If an offline mutation contains server-owned fields, the backend should reject those parts of the update.&lt;/p&gt;

&lt;p&gt;A field ownership model may 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fieldOwnership&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;approvedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;approvedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;complianceStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;localDraft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client can still display server-owned fields while offline.&lt;/p&gt;

&lt;p&gt;But it should not treat them as locally authoritative.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Overwrite
&lt;/h2&gt;

&lt;p&gt;Overwriting is acceptable when the business explicitly allows one side to win.&lt;/p&gt;

&lt;p&gt;For example, a user may edit a local draft on multiple devices, and the product may intentionally use the latest saved version.&lt;/p&gt;

&lt;p&gt;The important point is that overwrite should be a documented rule, not an accidental side effect.&lt;/p&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The latest request happened to win.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The architecture should say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This field uses last-write-wins because losing the earlier value is acceptable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;p&gt;An accidental overwrite is a bug.&lt;/p&gt;

&lt;p&gt;An intentional overwrite is a policy.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Review
&lt;/h2&gt;

&lt;p&gt;Some conflicts cannot be resolved safely by software.&lt;/p&gt;

&lt;p&gt;Consider these two changes:&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;// Technician update&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;inspectionResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SAFE&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Supervisor update&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;inspectionResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REQUIRES_REVIEW&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;Automatically choosing either version may create operational risk.&lt;/p&gt;

&lt;p&gt;The correct outcome may be to preserve both versions and require a person to resolve the conflict.&lt;/p&gt;

&lt;p&gt;A conflict record could 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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SyncConflict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entityId&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;field&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;localValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;serverValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;localUpdatedAt&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;serverUpdatedAt&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;resolutionStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RESOLVED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application can show a dedicated conflict-resolution screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspection result changed in two places.

Local version:
SAFE

Server version:
REQUIRES_REVIEW

Choose a value or escalate for supervisor review.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is less convenient than automatic synchronization.&lt;/p&gt;

&lt;p&gt;But convenience should not override correctness for critical data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use Version Numbers, Not Only Timestamps
&lt;/h2&gt;

&lt;p&gt;Timestamps are useful, but they are not always reliable enough for concurrency control.&lt;/p&gt;

&lt;p&gt;Devices may have incorrect clocks.&lt;/p&gt;

&lt;p&gt;Requests may be delayed.&lt;/p&gt;

&lt;p&gt;Two updates may happen within the same timestamp precision.&lt;/p&gt;

&lt;p&gt;A stronger approach is optimistic concurrency control using version numbers.&lt;/p&gt;

&lt;p&gt;The server stores:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REQ-1042&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPEN&lt;/span&gt;&lt;span class="dl"&gt;"&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="mi"&gt;4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client sends the version it originally edited:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;PATCH /maintenance-requests/REQ-1042
If-Match: 4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payload may contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IN_PROGRESS"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server still has version &lt;code&gt;4&lt;/code&gt;, the mutation can be accepted.&lt;/p&gt;

&lt;p&gt;The server updates the record to version &lt;code&gt;5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the server already has version &lt;code&gt;5&lt;/code&gt;, the client edited an outdated copy.&lt;/p&gt;

&lt;p&gt;The server can return a conflict response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;409 Conflict
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VERSION_CONFLICT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currentVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"serverRecord"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REQ-1042"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OPEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HIGH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client now has enough information to merge, reject, overwrite or request human review.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Simple React Native Mutation Queue
&lt;/h2&gt;

&lt;p&gt;An offline mutation should contain more than an endpoint and payload.&lt;/p&gt;

&lt;p&gt;It should also preserve the version that the user originally edited.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PendingMutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entityType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;maintenanceRequest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entityId&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;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;baseVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;createdAt&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;retryCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example mutation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PendingMutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mutation-501&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entityType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;maintenanceRequest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entityId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REQ-1042&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IN_PROGRESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inspection started at the site&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;retryCount&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During synchronization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syncMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PendingMutation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`/maintenance-requests/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entityId&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="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;PATCH&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;If-Match&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseVersion&lt;/span&gt;&lt;span class="p"&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;409&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;conflict&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CONFLICT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;serverRecord&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;conflict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serverRecord&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Sync failed with status &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="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;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;record&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that a &lt;code&gt;409 Conflict&lt;/code&gt; should not be treated like a normal retryable network error.&lt;/p&gt;

&lt;p&gt;Retrying the same request repeatedly will not resolve a semantic conflict.&lt;/p&gt;

&lt;p&gt;The system needs a conflict-resolution rule.&lt;/p&gt;




&lt;h2&gt;
  
  
  Classify Sync Failures Correctly
&lt;/h2&gt;

&lt;p&gt;Not every failed synchronization attempt means the same thing.&lt;/p&gt;

&lt;p&gt;A useful classification is:&lt;/p&gt;

&lt;h3&gt;
  
  
  Network failure
&lt;/h3&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no connectivity&lt;/li&gt;
&lt;li&gt;request timeout&lt;/li&gt;
&lt;li&gt;DNS failure&lt;/li&gt;
&lt;li&gt;temporary server unavailability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry with backoff&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authentication failure
&lt;/h3&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expired token&lt;/li&gt;
&lt;li&gt;revoked session&lt;/li&gt;
&lt;li&gt;missing permission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;refresh credentials or require authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Validation failure
&lt;/h3&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invalid field value&lt;/li&gt;
&lt;li&gt;required field missing&lt;/li&gt;
&lt;li&gt;unsupported state transition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;show the user what must be corrected&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Version conflict
&lt;/h3&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;server record changed after the local copy was created&lt;/li&gt;
&lt;li&gt;two users edited the same field&lt;/li&gt;
&lt;li&gt;an approval occurred while the device was offline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;merge, reject, overwrite or review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treating all four categories as “sync failed” creates weak architecture and confusing user experiences.&lt;/p&gt;




&lt;h2&gt;
  
  
  Do Not Delete the Local Mutation Too Early
&lt;/h2&gt;

&lt;p&gt;A dangerous synchronization pattern looks 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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;removeMutationFromQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is safe only when the server has confirmed that the mutation was accepted and correctly applied.&lt;/p&gt;

&lt;p&gt;The mutation should remain available when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the server returns a conflict&lt;/li&gt;
&lt;li&gt;only part of the payload was accepted&lt;/li&gt;
&lt;li&gt;conflict review is pending&lt;/li&gt;
&lt;li&gt;the response cannot be validated&lt;/li&gt;
&lt;li&gt;the application crashes before local state is updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A safer state machine might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MutationStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SYNCING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CONFLICT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COMPLETED&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;The queue entry should move to &lt;code&gt;COMPLETED&lt;/code&gt; only after the client has processed the final server response.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conflict Resolution Should Be Field-Aware
&lt;/h2&gt;

&lt;p&gt;Record-level conflict resolution is often too broad.&lt;/p&gt;

&lt;p&gt;Suppose the local version changes:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inspection completed&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;At the same time, the server changes:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HIGH&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;These updates affect different fields.&lt;/p&gt;

&lt;p&gt;Rejecting the entire local mutation would be unnecessary.&lt;/p&gt;

&lt;p&gt;A field-aware merge can preserve both changes:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inspection completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HIGH&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;But consider this case:&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;// Local&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COMPLETED&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CANCELLED&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;Both updates affect the same field.&lt;/p&gt;

&lt;p&gt;The conflict policy for &lt;code&gt;status&lt;/code&gt; must now decide whether to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reject the local transition&lt;/li&gt;
&lt;li&gt;keep the server value&lt;/li&gt;
&lt;li&gt;ask for review&lt;/li&gt;
&lt;li&gt;apply a domain-specific state machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why conflict resolution must understand business meaning, not only JSON structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Define the Rules Before Selecting the Database
&lt;/h2&gt;

&lt;p&gt;Teams often begin offline-first discussions with questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should we use Realm?&lt;/li&gt;
&lt;li&gt;Should we use SQLite?&lt;/li&gt;
&lt;li&gt;Should we use WatermelonDB?&lt;/li&gt;
&lt;li&gt;How should we structure the retry queue?&lt;/li&gt;
&lt;li&gt;Which connectivity library should we use?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are useful implementation questions.&lt;/p&gt;

&lt;p&gt;But they come after more important architecture questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which fields are client-owned?&lt;/li&gt;
&lt;li&gt;Which fields are server-owned?&lt;/li&gt;
&lt;li&gt;Which operations are append-only?&lt;/li&gt;
&lt;li&gt;Which fields can use last-write-wins?&lt;/li&gt;
&lt;li&gt;Which conflicts require human review?&lt;/li&gt;
&lt;li&gt;How long should unresolved conflicts be retained?&lt;/li&gt;
&lt;li&gt;Can users continue editing while a conflict is pending?&lt;/li&gt;
&lt;li&gt;What audit trail is required?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A database can persist conflicting data.&lt;/p&gt;

&lt;p&gt;It cannot decide which version is correct.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Practical Conflict-Policy Table
&lt;/h2&gt;

&lt;p&gt;Before implementation, document the policy for important fields.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field or Operation&lt;/th&gt;
&lt;th&gt;Ownership&lt;/th&gt;
&lt;th&gt;Resolution Strategy&lt;/th&gt;
&lt;th&gt;Human Review&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User notes&lt;/td&gt;
&lt;td&gt;Shared&lt;/td&gt;
&lt;td&gt;Last-write-wins or merge history&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approval status&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Reject local overwrite&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Activity log&lt;/td&gt;
&lt;td&gt;Append-only&lt;/td&gt;
&lt;td&gt;Merge&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspection result&lt;/td&gt;
&lt;td&gt;Shared&lt;/td&gt;
&lt;td&gt;Compare versions&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance status&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Server wins&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Draft description&lt;/td&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;Local overwrite allowed&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assigned technician&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Reject stale update&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This table becomes a shared contract between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mobile developers&lt;/li&gt;
&lt;li&gt;backend developers&lt;/li&gt;
&lt;li&gt;product managers&lt;/li&gt;
&lt;li&gt;QA engineers&lt;/li&gt;
&lt;li&gt;security teams&lt;/li&gt;
&lt;li&gt;compliance stakeholders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this contract, each layer may implement a different interpretation of “sync.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Questions to Ask During Architecture Review
&lt;/h2&gt;

&lt;p&gt;Before calling an application offline-first, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What happens when local and server records both change?&lt;/li&gt;
&lt;li&gt;Does every mutation include a base version?&lt;/li&gt;
&lt;li&gt;Which fields are controlled by the server?&lt;/li&gt;
&lt;li&gt;Which data can be merged safely?&lt;/li&gt;
&lt;li&gt;Which fields may use last-write-wins?&lt;/li&gt;
&lt;li&gt;Which conflicts must be reviewed by a person?&lt;/li&gt;
&lt;li&gt;Is conflict history preserved for auditing?&lt;/li&gt;
&lt;li&gt;Can the user see when synchronization is blocked?&lt;/li&gt;
&lt;li&gt;Are semantic conflicts separated from network failures?&lt;/li&gt;
&lt;li&gt;When is a mutation permanently removed from the queue?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the team cannot answer these questions, the application may support offline storage, but it does not yet have a complete offline-first architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Offline-first architecture is not only about local databases, queues and retry mechanisms.&lt;/p&gt;

&lt;p&gt;Those components answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How will data move when connectivity returns?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Conflict policies answer the more important question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What should happen when two valid versions disagree?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before building the synchronization engine, define four possible outcomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Merge. Reject. Overwrite. Review.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make those decisions per field or operation.&lt;/p&gt;

&lt;p&gt;Add version numbers to mutations.&lt;/p&gt;

&lt;p&gt;Keep unresolved conflicts visible.&lt;/p&gt;

&lt;p&gt;And never assume that a successful API response means the correct data survived.&lt;/p&gt;

&lt;p&gt;Which field in your application would be dangerous to resolve using last-write-wins?&lt;/p&gt;




</description>
      <category>reactnative</category>
      <category>mobilearchitecture</category>
      <category>architecture</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Your React Native Performance Problem May Actually Be a Memory Leak</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Sat, 11 Jul 2026 15:15:15 +0000</pubDate>
      <link>https://dev.to/subraatakumar/your-react-native-performance-problem-may-actually-be-a-memory-leak-1jpi</link>
      <guid>https://dev.to/subraatakumar/your-react-native-performance-problem-may-actually-be-a-memory-leak-1jpi</guid>
      <description>&lt;h1&gt;
  
  
  Your React Native Performance Problem May Actually Be a Memory Leak
&lt;/h1&gt;

&lt;p&gt;A React Native screen can render correctly and still leak memory.&lt;/p&gt;

&lt;p&gt;That is why some performance problems are misdiagnosed.&lt;/p&gt;

&lt;p&gt;The app feels fine after launch.&lt;/p&gt;

&lt;p&gt;Then, after repeated navigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;screens become slower&lt;/li&gt;
&lt;li&gt;callbacks fire more than once&lt;/li&gt;
&lt;li&gt;background work keeps increasing&lt;/li&gt;
&lt;li&gt;network listeners remain active&lt;/li&gt;
&lt;li&gt;timers continue running&lt;/li&gt;
&lt;li&gt;state updates happen after a screen has already unmounted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first reaction is often:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Let us optimise re-renders.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But re-rendering may not be the real problem.&lt;/p&gt;

&lt;p&gt;The actual issue may be that work created by old screens never stopped.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this is easy to misdiagnose
&lt;/h2&gt;

&lt;p&gt;Many React Native performance issues are visible immediately.&lt;/p&gt;

&lt;p&gt;A heavy component may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;render slowly&lt;/li&gt;
&lt;li&gt;block the JavaScript thread&lt;/li&gt;
&lt;li&gt;display a large list inefficiently&lt;/li&gt;
&lt;li&gt;perform expensive calculations during render&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Memory leaks often behave differently.&lt;/p&gt;

&lt;p&gt;They usually appear gradually.&lt;/p&gt;

&lt;p&gt;The first navigation works correctly.&lt;/p&gt;

&lt;p&gt;The second also looks fine.&lt;/p&gt;

&lt;p&gt;But after opening and closing the same screen multiple times, the application may start doing more work than expected.&lt;/p&gt;

&lt;p&gt;That gradual degradation makes the issue look like a rendering problem, even when the rendering logic has not changed.&lt;/p&gt;

&lt;p&gt;The important question is not only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is React rendering now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You also need to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the previous screen still doing?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A simple failure scenario
&lt;/h2&gt;

&lt;p&gt;Consider a screen that subscribes to an event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DeviceEventEmitter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;StatusScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;DeviceEventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;device-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Device status:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="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="kc"&gt;null&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;At first glance, this code looks harmless.&lt;/p&gt;

&lt;p&gt;The subscription is created only once for each mount because the dependency array is empty.&lt;/p&gt;

&lt;p&gt;But there is no cleanup.&lt;/p&gt;

&lt;p&gt;Each time the screen mounts, another listener is registered.&lt;/p&gt;

&lt;p&gt;After navigating to the screen five times, the same event may trigger five callbacks.&lt;/p&gt;

&lt;p&gt;The screen may not look broken, but the application is now doing unnecessary work.&lt;/p&gt;

&lt;p&gt;A safer version removes the listener during cleanup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DeviceEventEmitter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;StatusScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DeviceEventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;device-status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;status&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Device status:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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="kc"&gt;null&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;The important improvement is not in the render function.&lt;/p&gt;

&lt;p&gt;It is in the lifecycle ownership.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common sources of memory leaks in React Native
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Event listeners without cleanup
&lt;/h3&gt;

&lt;p&gt;Listeners are one of the most common causes of duplicated work.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DeviceEventEmitter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NativeEventEmitter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;keyboard listeners&lt;/li&gt;
&lt;li&gt;dimension listeners&lt;/li&gt;
&lt;li&gt;custom event buses&lt;/li&gt;
&lt;li&gt;navigation listeners&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common mistake is to register the listener correctly but forget to unsubscribe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Keyboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyboardDidShow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handleKeyboardShow&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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;Every listener should have a clear cleanup path.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Timers that survive screen unmount
&lt;/h3&gt;

&lt;p&gt;Intervals are especially risky because they continue executing until explicitly cleared.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intervalId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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="nf"&gt;refreshStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intervalId&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;Without cleanup, each screen visit may create another interval.&lt;/p&gt;

&lt;p&gt;The result may be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duplicate API requests&lt;/li&gt;
&lt;li&gt;repeated state updates&lt;/li&gt;
&lt;li&gt;unnecessary battery usage&lt;/li&gt;
&lt;li&gt;unexpected native module calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code may still appear correct during a short test session.&lt;/p&gt;

&lt;p&gt;The problem becomes visible only after repeated use.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. AppState and NetInfo subscriptions
&lt;/h3&gt;

&lt;p&gt;App lifecycle and connectivity listeners often live close to application-level logic.&lt;/p&gt;

&lt;p&gt;That makes ownership less obvious.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AppState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handleAppStateChange&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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;NetInfo has a similar subscription pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NetInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connected:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isConnected&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;unsubscribe&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;These subscriptions can be valid at the application level.&lt;/p&gt;

&lt;p&gt;The problem starts when the same global-style listener is created inside multiple screens or components.&lt;/p&gt;

&lt;p&gt;Before registering one, decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;should this listener exist once for the app?&lt;/li&gt;
&lt;li&gt;once per navigator?&lt;/li&gt;
&lt;li&gt;once per screen?&lt;/li&gt;
&lt;li&gt;once per active feature?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cleanup strategy depends on the ownership boundary.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Native module callbacks registered multiple times
&lt;/h3&gt;

&lt;p&gt;Native integration makes memory leaks harder to diagnose because the work may continue outside React.&lt;/p&gt;

&lt;p&gt;A native module may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;emit Bluetooth events&lt;/li&gt;
&lt;li&gt;report sensor data&lt;/li&gt;
&lt;li&gt;receive location updates&lt;/li&gt;
&lt;li&gt;send foreground service events&lt;/li&gt;
&lt;li&gt;notify JavaScript about background tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the JavaScript side registers the callback repeatedly, the native module may continue sending events to multiple active listeners.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NativeEventEmitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyNativeModule&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;measurement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handleMeasurement&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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;For native integrations, also verify whether cleanup is required on the native side.&lt;/p&gt;

&lt;p&gt;Removing the JavaScript listener may not be enough if the native service itself keeps running.&lt;/p&gt;

&lt;p&gt;Sometimes cleanup also requires calling methods such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;MyNativeModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopMonitoring&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct lifecycle may therefore look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MyNativeModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startMonitoring&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;emitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NativeEventEmitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyNativeModule&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;measurement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handleMeasurement&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;MyNativeModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopMonitoring&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;This is why memory ownership matters more than simply calling &lt;code&gt;remove()&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Async work completing after unmount
&lt;/h3&gt;

&lt;p&gt;Async operations do not always create a permanent memory leak, but they can still produce stale work and unnecessary updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetchProfile&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&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;If the user leaves the screen before the request finishes, the callback may run after unmount.&lt;/p&gt;

&lt;p&gt;A simple guard can prevent stale updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadProfile&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;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchProfile&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;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&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="nf"&gt;loadProfile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="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;For network requests, cancellation is often better when supported.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;fetch&lt;/code&gt;, you can use &lt;code&gt;AbortController&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadProfile&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&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;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setProfile&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AbortError&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;loadProfile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&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;This avoids unnecessary work instead of only ignoring the result.&lt;/p&gt;




&lt;h2&gt;
  
  
  The ownership questions every subscription should answer
&lt;/h2&gt;

&lt;p&gt;For every listener, timer, subscription or callback, identify four things.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Where is it created?
&lt;/h3&gt;

&lt;p&gt;Is it created inside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a screen&lt;/li&gt;
&lt;li&gt;a custom hook&lt;/li&gt;
&lt;li&gt;a context provider&lt;/li&gt;
&lt;li&gt;a navigation container&lt;/li&gt;
&lt;li&gt;an app-level service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tells you where cleanup should probably live.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Who owns it?
&lt;/h3&gt;

&lt;p&gt;Ownership should be explicit.&lt;/p&gt;

&lt;p&gt;A screen-level listener should normally disappear with the screen.&lt;/p&gt;

&lt;p&gt;An application-level listener may intentionally survive navigation.&lt;/p&gt;

&lt;p&gt;The problem is not long-lived work itself.&lt;/p&gt;

&lt;p&gt;The problem is long-lived work without clear ownership.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. When is it removed?
&lt;/h3&gt;

&lt;p&gt;Do not rely on assumptions.&lt;/p&gt;

&lt;p&gt;The cleanup path should be visible and testable.&lt;/p&gt;

&lt;p&gt;For React components, this often means returning a cleanup function from &lt;code&gt;useEffect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createResource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispose&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;
  
  
  4. Can it be registered more than once?
&lt;/h3&gt;

&lt;p&gt;This question catches many production issues.&lt;/p&gt;

&lt;p&gt;A listener may be duplicated because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the component mounts repeatedly&lt;/li&gt;
&lt;li&gt;the effect dependency changes&lt;/li&gt;
&lt;li&gt;a navigation listener is registered during focus&lt;/li&gt;
&lt;li&gt;a retry flow reinitialises the subscription&lt;/li&gt;
&lt;li&gt;a native module setup method is called more than once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always verify whether the registration is idempotent.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;useEffect&lt;/code&gt; dependencies can create hidden duplication
&lt;/h2&gt;

&lt;p&gt;A cleanup function alone does not guarantee correct behaviour.&lt;/p&gt;

&lt;p&gt;Consider this effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;handleEvent&lt;/code&gt; is recreated on every render, the effect may unsubscribe and resubscribe repeatedly.&lt;/p&gt;

&lt;p&gt;That may be valid, but it may also create unnecessary churn.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;useCallback&lt;/code&gt; when stable function identity is important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EventData&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;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;event&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The debugging question is not simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this effect have cleanup?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How often does this effect run, and how often does it recreate the resource?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Focus listeners require extra care
&lt;/h2&gt;

&lt;p&gt;React Navigation screens may remain mounted even when they are not focused.&lt;/p&gt;

&lt;p&gt;That means screen lifecycle and focus lifecycle are not always the same.&lt;/p&gt;

&lt;p&gt;If work should run only while the screen is active, &lt;code&gt;useFocusEffect&lt;/code&gt; may be a better fit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFocusEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-navigation/native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;useFocusEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;useCallback&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subscribeToLiveData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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;This ensures the subscription is active only while the screen is focused.&lt;/p&gt;

&lt;p&gt;Use this carefully.&lt;/p&gt;

&lt;p&gt;If the subscription should survive temporary navigation changes, screen-level focus cleanup may be too aggressive.&lt;/p&gt;

&lt;p&gt;The correct decision depends on ownership.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why render optimisation alone may not help
&lt;/h2&gt;

&lt;p&gt;Suppose you apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;React.memo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useMemo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useCallback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;list virtualisation&lt;/li&gt;
&lt;li&gt;smaller component trees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes can improve rendering.&lt;/p&gt;

&lt;p&gt;But they do not remove:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;old listeners&lt;/li&gt;
&lt;li&gt;duplicate timers&lt;/li&gt;
&lt;li&gt;native callbacks&lt;/li&gt;
&lt;li&gt;background services&lt;/li&gt;
&lt;li&gt;stale async tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may make the current screen render faster while previous screens continue consuming resources.&lt;/p&gt;

&lt;p&gt;That is why profiling only render behaviour can give an incomplete picture.&lt;/p&gt;

&lt;p&gt;Render profiling tells you what React is doing now.&lt;/p&gt;

&lt;p&gt;Lifecycle debugging tells you what earlier components may still be doing.&lt;/p&gt;

&lt;p&gt;You need both.&lt;/p&gt;




&lt;h2&gt;
  
  
  A practical debugging process
&lt;/h2&gt;

&lt;p&gt;When a React Native app becomes slower after repeated navigation, use a repeatable process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Reproduce the degradation
&lt;/h3&gt;

&lt;p&gt;Do not test only from a fresh launch.&lt;/p&gt;

&lt;p&gt;Repeat the same flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;open the screen&lt;/li&gt;
&lt;li&gt;leave the screen&lt;/li&gt;
&lt;li&gt;open it again&lt;/li&gt;
&lt;li&gt;repeat several times&lt;/li&gt;
&lt;li&gt;trigger the same event or action&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Look for callbacks that increase with every cycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add temporary registration logs
&lt;/h3&gt;

&lt;p&gt;Log when resources are created and removed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Registering device listener&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;registerDeviceListener&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Removing device listener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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;For each registration, you should see a corresponding cleanup when expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Count callback executions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;callbackCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;callbackCount&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Callback count:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callbackCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a single event triggers multiple callbacks after repeated navigation, duplicate listeners are likely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Inspect timers and polling
&lt;/h3&gt;

&lt;p&gt;Search for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setInterval&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;recursive polling&lt;/li&gt;
&lt;li&gt;retry loops&lt;/li&gt;
&lt;li&gt;animation loops&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm that each one is cancelled correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Inspect native services
&lt;/h3&gt;

&lt;p&gt;Check whether native modules continue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scanning&lt;/li&gt;
&lt;li&gt;observing&lt;/li&gt;
&lt;li&gt;polling&lt;/li&gt;
&lt;li&gt;emitting events&lt;/li&gt;
&lt;li&gt;tracking location&lt;/li&gt;
&lt;li&gt;maintaining sockets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JavaScript cleanup may not stop native work automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Profile memory and activity
&lt;/h3&gt;

&lt;p&gt;Use platform tools when the issue is not obvious.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Android Studio Profiler&lt;/li&gt;
&lt;li&gt;Memory Profiler&lt;/li&gt;
&lt;li&gt;CPU Profiler&lt;/li&gt;
&lt;li&gt;Logcat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For iOS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Xcode Instruments&lt;/li&gt;
&lt;li&gt;Allocations&lt;/li&gt;
&lt;li&gt;Leaks&lt;/li&gt;
&lt;li&gt;Time Profiler&lt;/li&gt;
&lt;li&gt;Energy Log&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also use React Native tooling where useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React DevTools&lt;/li&gt;
&lt;li&gt;Hermes profiling&lt;/li&gt;
&lt;li&gt;Flipper, where supported by the project setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not only to see memory growth.&lt;/p&gt;

&lt;p&gt;Also check whether the number of callbacks, subscriptions or native operations grows with each navigation cycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  A cleanup checklist for code review
&lt;/h2&gt;

&lt;p&gt;When reviewing React Native lifecycle code, ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does every listener have an unsubscribe path?&lt;/li&gt;
&lt;li&gt;Does every interval have a &lt;code&gt;clearInterval&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Does every timeout have a &lt;code&gt;clearTimeout&lt;/code&gt; where required?&lt;/li&gt;
&lt;li&gt;Does every native subscription expose disposal?&lt;/li&gt;
&lt;li&gt;Does every background service have a stop method?&lt;/li&gt;
&lt;li&gt;Can this effect register more than once?&lt;/li&gt;
&lt;li&gt;Should this resource follow mount lifecycle or focus lifecycle?&lt;/li&gt;
&lt;li&gt;Can async work be cancelled?&lt;/li&gt;
&lt;li&gt;Can stale results update state?&lt;/li&gt;
&lt;li&gt;Is this subscription owned by the correct architectural layer?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This checklist is more useful than asking only whether &lt;code&gt;useEffect&lt;/code&gt; has a return function.&lt;/p&gt;

&lt;p&gt;Cleanup is not just syntax.&lt;/p&gt;

&lt;p&gt;It is an ownership decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  A stronger engineering rule
&lt;/h2&gt;

&lt;p&gt;Before optimising rendering, check whether the screen leaves behind any long-lived work.&lt;/p&gt;

&lt;p&gt;For every subscription, answer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where is it created?&lt;/li&gt;
&lt;li&gt;Who owns it?&lt;/li&gt;
&lt;li&gt;When is it removed?&lt;/li&gt;
&lt;li&gt;Can it be registered more than once?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A component may render perfectly and still damage performance over time.&lt;/p&gt;

&lt;p&gt;The leak often exists outside the visible render path.&lt;/p&gt;

&lt;p&gt;That is why repeated navigation is such an important test.&lt;/p&gt;

&lt;p&gt;A fresh launch shows whether the screen works.&lt;/p&gt;

&lt;p&gt;Repeated use shows whether the lifecycle works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Not every slow React Native screen needs render optimisation.&lt;/p&gt;

&lt;p&gt;Sometimes the screen is slow because previous screens are still alive through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;listeners&lt;/li&gt;
&lt;li&gt;timers&lt;/li&gt;
&lt;li&gt;subscriptions&lt;/li&gt;
&lt;li&gt;native callbacks&lt;/li&gt;
&lt;li&gt;background tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Render profiling tells you what React is doing now.&lt;/p&gt;

&lt;p&gt;Lifecycle cleanup tells you what old work never stopped.&lt;/p&gt;

&lt;p&gt;When a React Native app becomes slower after repeated navigation, which cleanup path do you inspect first?&lt;/p&gt;




</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Add Web Search Tool to AI Agent | Tool Calling Explained | Microsoft Foundry AI Agent Tutorial #6</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:20:56 +0000</pubDate>
      <link>https://dev.to/subraatakumar/add-web-search-tool-to-ai-agent-tool-calling-explained-microsoft-foundry-ai-agent-tutorial-6-2f3j</link>
      <guid>https://dev.to/subraatakumar/add-web-search-tool-to-ai-agent-tool-calling-explained-microsoft-foundry-ai-agent-tutorial-6-2f3j</guid>
      <description></description>
      <category>ai</category>
      <category>subraatakumar</category>
    </item>
    <item>
      <title>Deploy Your First AI Model in Microsoft Foundry | System Prompts Explained | AI Agent Course #5</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:18:12 +0000</pubDate>
      <link>https://dev.to/subraatakumar/deploy-your-first-ai-model-in-microsoft-foundry-system-prompts-explained-ai-agent-course-5-475p</link>
      <guid>https://dev.to/subraatakumar/deploy-your-first-ai-model-in-microsoft-foundry-system-prompts-explained-ai-agent-course-5-475p</guid>
      <description></description>
      <category>ai</category>
      <category>azure</category>
      <category>subraatakumar</category>
    </item>
    <item>
      <title>Microsoft Foundry Setup Tutorial | Create Your First AI Agent Project (Azure AI Foundry Course) #4</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:16:35 +0000</pubDate>
      <link>https://dev.to/subraatakumar/microsoft-foundry-setup-tutorial-create-your-first-ai-agent-project-azure-ai-foundry-course-4-28ge</link>
      <guid>https://dev.to/subraatakumar/microsoft-foundry-setup-tutorial-create-your-first-ai-agent-project-azure-ai-foundry-course-4-28ge</guid>
      <description></description>
    </item>
    <item>
      <title>What is an AI Agent? AI Agent vs Chatbot Explained | Microsoft Foundry Course #3</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:14:54 +0000</pubDate>
      <link>https://dev.to/subraatakumar/what-is-an-ai-agent-ai-agent-vs-chatbot-explained-microsoft-foundry-course-3-2fjd</link>
      <guid>https://dev.to/subraatakumar/what-is-an-ai-agent-ai-agent-vs-chatbot-explained-microsoft-foundry-course-3-2fjd</guid>
      <description></description>
      <category>ai</category>
      <category>azure</category>
      <category>beginners</category>
      <category>subrata</category>
    </item>
    <item>
      <title>What is Generative AI? Understanding the Foundation of Modern AI Agents #2</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Fri, 19 Jun 2026 06:20:04 +0000</pubDate>
      <link>https://dev.to/subraatakumar/what-is-generative-ai-understanding-the-foundation-of-modern-ai-agents-2-3jgn</link>
      <guid>https://dev.to/subraatakumar/what-is-generative-ai-understanding-the-foundation-of-modern-ai-agents-2-3jgn</guid>
      <description>&lt;p&gt;Everyone is talking about AI Agents.&lt;/p&gt;

&lt;p&gt;But before you build an AI Agent, there is one concept you absolutely need to understand:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generative AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generative AI is the technology that transformed software from systems that simply follow rules into systems that can understand language, generate responses, reason through instructions, and assist users in a natural way.&lt;/p&gt;

&lt;p&gt;As part of my new course:&lt;/p&gt;

&lt;h2&gt;
  
  
  Develop Your First AI Agent with Microsoft Foundry
&lt;/h2&gt;

&lt;p&gt;I published the first lesson where we explore the journey from traditional software to Generative AI and understand why modern AI Agents became possible.&lt;/p&gt;

&lt;p&gt;🎥 &lt;strong&gt;Watch the video here:&lt;/strong&gt;&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/aGmA574q_FQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Topic Matters
&lt;/h2&gt;

&lt;p&gt;Many developers jump directly into AI Agents, prompts, tools, and frameworks.&lt;/p&gt;

&lt;p&gt;However, without understanding the evolution of AI, it becomes difficult to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why AI Agents exist&lt;/li&gt;
&lt;li&gt;Why Large Language Models are important&lt;/li&gt;
&lt;li&gt;Why prompts work&lt;/li&gt;
&lt;li&gt;Why tools are needed&lt;/li&gt;
&lt;li&gt;How modern AI systems actually operate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this lesson, we start from first principles and build the foundation required for the rest of the course.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Traditional Software
&lt;/h3&gt;

&lt;p&gt;For decades, software followed a simple pattern:&lt;/p&gt;

&lt;p&gt;Input → Rules → Output&lt;/p&gt;

&lt;p&gt;Developers explicitly defined every behavior.&lt;/p&gt;

&lt;p&gt;This worked well until humans started interacting with software using natural language.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Rule-Based Systems Break
&lt;/h3&gt;

&lt;p&gt;Imagine building a dietician chatbot.&lt;/p&gt;

&lt;p&gt;Users might ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What should I eat?&lt;/li&gt;
&lt;li&gt;Suggest a healthy breakfast.&lt;/li&gt;
&lt;li&gt;What foods contain protein?&lt;/li&gt;
&lt;li&gt;Can I eat oats daily?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these questions are similar.&lt;/p&gt;

&lt;p&gt;Yet they are phrased differently.&lt;/p&gt;

&lt;p&gt;Supporting thousands of variations quickly becomes impossible with manually written rules.&lt;/p&gt;




&lt;h3&gt;
  
  
  Predictive AI
&lt;/h3&gt;

&lt;p&gt;Machine Learning introduced a new approach.&lt;/p&gt;

&lt;p&gt;Instead of writing rules, we train models using data.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spam Detection&lt;/li&gt;
&lt;li&gt;Fraud Detection&lt;/li&gt;
&lt;li&gt;Recommendation Systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Predictive AI can make decisions.&lt;/p&gt;

&lt;p&gt;But it still cannot create content.&lt;/p&gt;




&lt;h3&gt;
  
  
  Prediction vs Creation
&lt;/h3&gt;

&lt;p&gt;A predictive model can answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fraud probability: 87%&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But can it explain why?&lt;/p&gt;

&lt;p&gt;Can it write a detailed report?&lt;/p&gt;

&lt;p&gt;Can it create a personalized recommendation?&lt;/p&gt;

&lt;p&gt;Not naturally.&lt;/p&gt;

&lt;p&gt;This limitation led to the rise of Generative AI.&lt;/p&gt;




&lt;h3&gt;
  
  
  Generative AI
&lt;/h3&gt;

&lt;p&gt;Generative AI creates new content.&lt;/p&gt;

&lt;p&gt;It can generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Audio&lt;/li&gt;
&lt;li&gt;Video&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of selecting predefined responses, it dynamically creates new outputs based on user prompts.&lt;/p&gt;




&lt;h3&gt;
  
  
  Large Language Models (LLMs)
&lt;/h3&gt;

&lt;p&gt;At the heart of Generative AI are Large Language Models.&lt;/p&gt;

&lt;p&gt;LLMs learn language patterns from enormous amounts of data and use those patterns to generate human-like responses.&lt;/p&gt;

&lt;p&gt;This is the technology behind modern AI systems such as ChatGPT, Microsoft Copilot, Gemini, Claude, and many others.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Generative AI Flow
&lt;/h3&gt;

&lt;p&gt;Every Generative AI application follows a simple architecture:&lt;/p&gt;

&lt;p&gt;User Prompt → LLM → Generated Response&lt;/p&gt;

&lt;p&gt;Understanding this flow is critical because it becomes the foundation of AI Agent architectures.&lt;/p&gt;




&lt;h3&gt;
  
  
  AI Agent Architecture
&lt;/h3&gt;

&lt;p&gt;In the second half of the course, we will build an AI Agent using Microsoft Foundry.&lt;/p&gt;

&lt;p&gt;The architecture we'll implement is:&lt;/p&gt;

&lt;p&gt;User&lt;br&gt;
↓&lt;br&gt;
React + Vite Frontend&lt;br&gt;
↓&lt;br&gt;
Microsoft Foundry Agent&lt;br&gt;
├── Instructions&lt;br&gt;
├── Generative AI Model&lt;br&gt;
└── Web Search Tool&lt;br&gt;
↓&lt;br&gt;
Response&lt;/p&gt;

&lt;p&gt;Understanding Generative AI is the first step toward understanding this architecture.&lt;/p&gt;




&lt;h3&gt;
  
  
  Introducing Subra AI Dietician
&lt;/h3&gt;

&lt;p&gt;Throughout the course, we will build:&lt;/p&gt;

&lt;h2&gt;
  
  
  Subra AI Dietician
&lt;/h2&gt;

&lt;p&gt;A practical AI-powered dietician assistant that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answer nutrition questions&lt;/li&gt;
&lt;li&gt;Provide healthy food suggestions&lt;/li&gt;
&lt;li&gt;Follow custom instructions&lt;/li&gt;
&lt;li&gt;Use web search when required&lt;/li&gt;
&lt;li&gt;Respond through a modern web interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of the course, you'll have a complete working AI Agent built using Microsoft Foundry.&lt;/p&gt;




&lt;h2&gt;
  
  
  Video Chapters
&lt;/h2&gt;

&lt;p&gt;00:00 Introduction&lt;/p&gt;

&lt;p&gt;01:30 The Problem With Traditional Software&lt;/p&gt;

&lt;p&gt;02:30 Why Rule-Based Systems Break&lt;/p&gt;

&lt;p&gt;03:51 The Rise of Predictive AI&lt;/p&gt;

&lt;p&gt;05:06 Prediction vs Creation&lt;/p&gt;

&lt;p&gt;05:55 What is Generative AI&lt;/p&gt;

&lt;p&gt;06:43 What is LLM?&lt;/p&gt;

&lt;p&gt;07:36 The Generative AI Flow&lt;/p&gt;

&lt;p&gt;08:18 AI Agent Architecture&lt;/p&gt;

&lt;p&gt;09:06 Subra AI Dietician&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Coming Next?
&lt;/h2&gt;

&lt;p&gt;In the next lesson, we'll answer a very important question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If Generative AI can already answer questions, why do we need AI Agents?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI Assistant vs AI Agent&lt;/li&gt;
&lt;li&gt;Instructions&lt;/li&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;Reasoning&lt;/li&gt;
&lt;li&gt;Agent Workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and prepare for building our first Microsoft Foundry Agent.&lt;/p&gt;

&lt;p&gt;If you're interested in AI Engineering, Microsoft Foundry, Azure AI, Agentic AI, or building practical AI applications, this series is designed for you.&lt;/p&gt;

&lt;p&gt;Happy learning!&lt;/p&gt;

&lt;p&gt;— Subrata Kumar Das&lt;br&gt;
🌐 subraatakumar.com&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>microsoft</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Develop Your First AI Agent with Microsoft Foundry</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Thu, 18 Jun 2026 06:11:35 +0000</pubDate>
      <link>https://dev.to/subraatakumar/develop-your-first-ai-agent-with-microsoft-foundry-2ben</link>
      <guid>https://dev.to/subraatakumar/develop-your-first-ai-agent-with-microsoft-foundry-2ben</guid>
      <description>&lt;h1&gt;
  
  
  Develop Your First AI Agent with Microsoft Foundry – Course Launch
&lt;/h1&gt;

&lt;p&gt;AI Agents are quickly moving from experimental technology to real-world software engineering solutions.&lt;/p&gt;

&lt;p&gt;As developers, we are entering a phase where applications can not only respond to user input but also reason, use tools, search for information, and perform tasks on behalf of users.&lt;/p&gt;

&lt;p&gt;To help software engineers get started with this technology, I've launched a new hands-on course:&lt;/p&gt;

&lt;h2&gt;
  
  
  Develop Your First AI Agent with Microsoft Foundry
&lt;/h2&gt;

&lt;p&gt;This course focuses on practical implementation rather than AI theory.&lt;/p&gt;

&lt;p&gt;Throughout the series, we'll build a complete application called &lt;strong&gt;Subra AI Dietician&lt;/strong&gt;, an intelligent AI Agent powered by Microsoft Foundry and Azure AI Foundry Agent Service.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Build
&lt;/h2&gt;

&lt;p&gt;By the end of the course, you'll have built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Microsoft Foundry AI Agent&lt;/li&gt;
&lt;li&gt;Custom Agent Instructions&lt;/li&gt;
&lt;li&gt;Web Search Tool Integration&lt;/li&gt;
&lt;li&gt;Agent Testing and Evaluation&lt;/li&gt;
&lt;li&gt;A Deployed AI Agent&lt;/li&gt;
&lt;li&gt;A React Frontend Connected to the Agent&lt;/li&gt;
&lt;li&gt;A Complete End-to-End AI Application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technology Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Foundry&lt;/li&gt;
&lt;li&gt;Azure AI Foundry Agent Service&lt;/li&gt;
&lt;li&gt;Visual Studio Code&lt;/li&gt;
&lt;li&gt;GitHub Copilot&lt;/li&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who Is This Course For?
&lt;/h2&gt;

&lt;p&gt;This course is designed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Engineers&lt;/li&gt;
&lt;li&gt;React Developers&lt;/li&gt;
&lt;li&gt;React Native Developers&lt;/li&gt;
&lt;li&gt;Full Stack Developers&lt;/li&gt;
&lt;li&gt;Technical Leads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No prior AI experience is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 1 Is Now Available
&lt;/h2&gt;

&lt;p&gt;The first lesson introduces the course, explains what we'll build, and walks through the complete project roadmap.&lt;/p&gt;

&lt;p&gt;📺 Watch the video:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/qILE6NUEsQU"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;🌐 Course Website:&lt;br&gt;
&lt;a href="https://rnm.subraatakumar.com" rel="noopener noreferrer"&gt;https://rnm.subraatakumar.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;In the next lesson, we'll answer an important question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What exactly is an AI Agent, and how is it different from traditional software applications?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear from the community:&lt;/p&gt;

&lt;p&gt;What AI Agent would you build for your organization or personal projects?&lt;/p&gt;

&lt;h1&gt;
  
  
  ai #microsoft #azure #aifoundry #microsoftfoundry #aiagents #softwareengineering #react #reactnative #webdevelopment #githubcopilot
&lt;/h1&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>microsoft</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Lesson 1.3 - GraphQL for Screen Complexity and App Changes</title>
      <dc:creator>Subrata Kumar Das</dc:creator>
      <pubDate>Wed, 17 Jun 2026 05:07:25 +0000</pubDate>
      <link>https://dev.to/subraatakumar/lesson-13-graphql-for-screen-complexity-and-app-changes-3cdi</link>
      <guid>https://dev.to/subraatakumar/lesson-13-graphql-for-screen-complexity-and-app-changes-3cdi</guid>
      <description>&lt;p&gt;Good morning, class! Welcome back. In our last lesson, we explored how GraphQL fundamentally addresses the issues of over-fetching and under-fetching.&lt;/p&gt;

&lt;p&gt;Today, we are going to connect those architectural concepts directly to real-world React Native screen complexity. Our &lt;strong&gt;Goal&lt;/strong&gt; today is to understand how GraphQL simplifies your codebase when a screen demands multiple data sources, when different screens require entirely unique variations of the same resource, and when your mobile application changes and evolves over time.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Problem One: Codebase Complexity via Multiple API Calls
&lt;/h2&gt;

&lt;p&gt;Making multiple API calls is not inherently wrong, but from a mobile product engineering perspective, it introduces a significant amount of state-tracking boilerplate inside your components.&lt;/p&gt;

&lt;p&gt;In a traditional React Native screen driven by REST, managing multiple endpoints often forces you into a state management pattern that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProducts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCategories&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;loadingProducts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoadingProducts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loadingCategories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoadingCategories&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;productsError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProductsError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;categoriesError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCategoriesError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Class, look closely at this block of code. We haven't even written a single line of JSX or rendered any UI yet, and our component is already drowning in individual state hooks just to track the network layer.&lt;/p&gt;

&lt;p&gt;The moment a single screen relies on multiple independent asynchronous requests, you are forced to programmatically answer complex state orchestration questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the &lt;em&gt;entire&lt;/em&gt; screen considered to be in a loading state, or are individual sub-sections loading independently?&lt;/li&gt;
&lt;li&gt;What happens visually if the product list resolves successfully, but the category chip request fails?&lt;/li&gt;
&lt;li&gt;When a user triggers a pull-to-refresh action, should it aggressively retry every single request?&lt;/li&gt;
&lt;li&gt;Should a localized network failure on a non-critical widget block the user from interacting with the rest of the screen?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. GraphQL Fix One: Consolidated Screen-Level Operations
&lt;/h2&gt;

&lt;p&gt;Instead of forcing your UI components to orchestrate several disconnected REST endpoints, a single GraphQL operation lets you fetch the precise combination of data pieces your screen needs in one single network round-trip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HomeScreenData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, let's be entirely clear: this does not magically erase the necessity for loading spinners or error screens. You still need to design and implement resilient UI fallbacks.&lt;/p&gt;

&lt;p&gt;However, it vastly simplifies your frontend state logic. It collapses multiple asynchronous workflows down into &lt;strong&gt;one single operation&lt;/strong&gt; for your component to reason about, dramatically reducing the state variables you need to manually track.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Problem Two: Screen-Specific Data Requirements
&lt;/h2&gt;

&lt;p&gt;As an application grows, different mobile screens will inevitably demand entirely different variations of the exact same data model. Let’s map out a standard e-commerce flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Product List Screen Layout:&lt;/strong&gt; Only needs &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, and &lt;code&gt;imageUrl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product Details Screen Layout:&lt;/strong&gt; Requires &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;imageUrl&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;brand&lt;/code&gt;, &lt;code&gt;rating&lt;/code&gt;, &lt;code&gt;discount&lt;/code&gt;, and &lt;code&gt;inStock&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cart Summary Screen Layout:&lt;/strong&gt; Demands &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt;, and &lt;code&gt;inStock&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a traditional REST architecture, backend teams typically handle these evolving variations by creating specific hyper-targeted endpoints (like &lt;code&gt;/api/v1/products/cart-view&lt;/code&gt;) or by adding heavy configurations of query parameters (like &lt;code&gt;/products?include=details&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;While this can get the job done, over time it causes your API surface area to balloon into a tangled, unmanageable mess simply because every new screen design requires a slightly modified data payload shape.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. GraphQL Fix Two: Component-Driven Selection Sets
&lt;/h2&gt;

&lt;p&gt;GraphQL shifts data model ownership back to the client application. Instead of waiting on backend adjustments, &lt;strong&gt;each specific screen explicitly declares its own data requirements.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, you can parameterize these operations dynamically using &lt;strong&gt;GraphQL Variables&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductListScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;inStock&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;To execute this operation with dynamic filtering, you pass a separate &lt;strong&gt;Variables object&lt;/strong&gt; alongside the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fruits"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;The underlying structural template of the query remains completely stable. The runtime variables change fluidly based on user interaction. This exact paradigm is exactly what makes building mobile filters, search views, and infinite-scrolling lists highly predictable and clean.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Problem Three: The Production Reality of App Versioning
&lt;/h2&gt;

&lt;p&gt;Unlike web applications where a new deployment updates all users instantly, mobile applications stay installed on user devices for months or even years.&lt;/p&gt;

&lt;p&gt;If a backend team alters or refactors a REST response payload, older, un-updated installations of your mobile app out in the wild can instantly crash. Because of this, mobile engineering teams are traditionally forced to implement strict, complex API versioning policies (like &lt;code&gt;/api/v1/&lt;/code&gt; vs &lt;code&gt;/api/v2/&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;GraphQL does not replace architectural discipline, but it offers natural protection against breaking changes because &lt;strong&gt;the client must explicitly request the fields it intends to use.&lt;/strong&gt; If an older mobile app build doesn't know about a new &lt;code&gt;rating&lt;/code&gt; field, it simply won't request it. If a newer build needs to display it, you append it inline without affecting old versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductCards&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;rating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Added seamlessly for new app versions&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Because the backend server knows exactly which fields are being requested by current active users, the client app is no longer tightly coupled to a monolithic, fixed response shape.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. The Blueprint: Predictable Response Mirroring
&lt;/h2&gt;

&lt;p&gt;One of the most beginner-friendly and elegant aspects of working with GraphQL is that &lt;strong&gt;the response payload shape directly mirrors your request query structure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s trace an active transaction:&lt;/p&gt;

&lt;h3&gt;
  
  
  Client Query Document:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CategoriesAndProducts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  JSON Server Response:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"categories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Fruits"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Vegetables"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apple"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tomato"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;While the literal data values inside the strings and arrays will change based on database records, the structural nesting matches your query word-for-word, making data binding inside React Native components entirely intuitive.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Guided Practice in GraphiQL
&lt;/h2&gt;

&lt;p&gt;Before we jump back into our mobile IDEs, let's build muscular memory by sandbox testing this query layout inside GraphiQL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate your web browser to &lt;code&gt;https://backend.ecom.subraatakumar.com/graphiql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paste the parameterized &lt;code&gt;ProductListScreen&lt;/code&gt; query into the main editor panel.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Query Variables&lt;/strong&gt; drawer at the bottom left and pass valid page/category variables.&lt;/li&gt;
&lt;li&gt;Hit the &lt;strong&gt;Play&lt;/strong&gt; button to execute.&lt;/li&gt;
&lt;li&gt;Experiment: adjust the &lt;code&gt;category&lt;/code&gt; string to another value and re-run.&lt;/li&gt;
&lt;li&gt;Delete &lt;code&gt;imageUrl&lt;/code&gt; from the selection set and observe the updated JSON structure.&lt;/li&gt;
&lt;li&gt;Append &lt;code&gt;rating&lt;/code&gt; to the selection set, execute, and verify the structural response mirrors your query change instantly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This iterative feedback loop is the core day-to-day workflow of a productive GraphQL developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. React Native Low-Level Implementation
&lt;/h2&gt;

&lt;p&gt;Let’s observe how this complete multi-resource request compiles into a low-level JavaScript module using our temporary native &lt;code&gt;fetch&lt;/code&gt; client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadProductList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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://backend.ecom.subraatakumar.com/graphql&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;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="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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        query ProductListScreen($page: Int!, $size: Int!, $category: String) {
          products(page: $page, size: $size, category: $category) {
            meta {
              total
              page
              pages
            }
            data {
              id
              name
              price
              imageUrl
              inStock
            }
          }
        }
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&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;message&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;json&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;products&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Check Your Understanding
&lt;/h2&gt;

&lt;p&gt;Before we wrap up this theory session and head into our practical labs, make sure you can answer these three questions clearly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do multiple independent REST calls compound the structural complexity of component loading and error states in React Native?&lt;/li&gt;
&lt;li&gt;What does it mean for a screen to "own its data requirement," and how does this prevent API endpoint bloat on the backend?&lt;/li&gt;
&lt;li&gt;What is the relationship between the structural layout of a GraphQL query document and the eventual JSON payload returned by the server?&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Great work today, class. Review your notes, spend 10 minutes testing variations in the GraphiQL playground, and I will see you all in our next session!&lt;/p&gt;




&lt;p&gt;Connect with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/TechCraft-By-Subrata" rel="noopener noreferrer"&gt;https://github.com/TechCraft-By-Subrata&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/subraatakumar/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/subraatakumar/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;YouTube: &lt;a href="https://www.youtube.com/@techcraftclub" rel="noopener noreferrer"&gt;https://www.youtube.com/@techcraftclub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Instagram: &lt;a href="https://www.instagram.com/subraatakumar/" rel="noopener noreferrer"&gt;https://www.instagram.com/subraatakumar/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Reddit: &lt;a href="https://www.reddit.com/r/ReactNativeMastery/" rel="noopener noreferrer"&gt;https://www.reddit.com/r/ReactNativeMastery/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV.to: &lt;a href="https://dev.to/subraatakumar"&gt;https://dev.to/subraatakumar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Discord: &lt;a href="https://discord.gg/cA5fhVT8" rel="noopener noreferrer"&gt;https://discord.gg/cA5fhVT8&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;WhatsApp: &lt;a href="https://whatsapp.com/channel/0029VbCz72vFCCoUsMV4K30M" rel="noopener noreferrer"&gt;https://whatsapp.com/channel/0029VbCz72vFCCoUsMV4K30M&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Topmate: &lt;a href="https://topmate.io/subrata" rel="noopener noreferrer"&gt;https://topmate.io/subrata&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;React Native Mastery: &lt;a href="https://rnm.subraatakumar.com/" rel="noopener noreferrer"&gt;https://rnm.subraatakumar.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>mobile</category>
      <category>reactnative</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
