<?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: Suyash Vashishtha</title>
    <description>The latest articles on DEV Community by Suyash Vashishtha (@suyashdev).</description>
    <link>https://dev.to/suyashdev</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%2F744686%2F5c614616-c18e-4cc5-a21c-d845e0390638.png</url>
      <title>DEV Community: Suyash Vashishtha</title>
      <link>https://dev.to/suyashdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suyashdev"/>
    <language>en</language>
    <item>
      <title>I Shipped an Play Store App That Updates Itself, Because There's Nothing in It to Update</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Tue, 08 Sep 2026 07:53:00 +0000</pubDate>
      <link>https://dev.to/suyashdev/i-shipped-an-play-store-app-that-updates-itself-because-theres-nothing-in-it-to-update-529i</link>
      <guid>https://dev.to/suyashdev/i-shipped-an-play-store-app-that-updates-itself-because-theres-nothing-in-it-to-update-529i</guid>
      <description>&lt;p&gt;&lt;code&gt;com.myvitals.app&lt;/code&gt;, installed from the Play Store, icon and splash screen and everything, has almost no native UI. Open the source: a splash screen, an error screen, one &lt;code&gt;WebView&lt;/code&gt; pointed at &lt;code&gt;https://myvitals.co.in&lt;/code&gt;. That's the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WEBVIEW_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://myvitals.co.in&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;That string is functionally the entire product. Ship a fix to the web frontend — a normal deploy — and every installed app gets it next open. No review queue, no staged rollout, no "update available" nag. The native shell itself changes maybe a few times a year (a permission, an icon); everything users experience as "the app" ships at web speed, to 100% of installs, at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trade
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No true offline bundle&lt;/strong&gt; — if the WebView can't reach the internet on first paint, there's nothing local to fall back to. (The actual offline story lives entirely on the web side — service worker + IndexedDB, &lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;covered separately&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You inherit WebView quirks&lt;/strong&gt; — &lt;code&gt;env(safe-area-inset-*)&lt;/code&gt; often resolves to &lt;code&gt;0&lt;/code&gt; even with &lt;code&gt;viewport-fit=cover&lt;/code&gt; set. Fix: stack a fixed minimum padding on top of the CSS value instead of trusting it alone.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  "Finished loading" ≠ "actually works"
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;onLoadEnd&lt;/code&gt; means "navigation finished," not "a human would call this working" — for a React SPA, the shell can be blank while JS boots. So there's a second signal: a 15-second timer, and if still loading when it fires, that's a failure regardless of what the WebView reported.&lt;/p&gt;

&lt;p&gt;The real gotcha: &lt;code&gt;onLoadEnd&lt;/code&gt; fires &lt;strong&gt;after &lt;code&gt;onError&lt;/code&gt; too&lt;/strong&gt; — it's "did-finish," not success-only. Wire it naively and a failed load flashes an error screen then un-fails itself a moment later. Fix is one ref, set the instant an error fires, checked before allowing success to override it.&lt;/p&gt;

&lt;p&gt;Retry doesn't call &lt;code&gt;.reload()&lt;/code&gt; — it bumps a &lt;code&gt;key&lt;/code&gt; prop and lets React fully remount the WebView, after checking real connectivity first. A stale WebView instance can wedge itself into states a soft reload won't clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bridging the back button
&lt;/h2&gt;

&lt;p&gt;Android's hardware back button should navigate the website's own history. Track &lt;code&gt;canGoBack&lt;/code&gt; from WebView nav state; on back-press, call &lt;code&gt;goBack()&lt;/code&gt; if there's history — and explicitly do &lt;strong&gt;nothing&lt;/strong&gt; (let the OS exit the app) if there isn't. Swallowing back-press unconditionally traps users on a screen with a dead back button, which is worse than not intercepting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making a website stop feeling clickable
&lt;/h2&gt;

&lt;p&gt;Injected JS disables text selection and long-press callouts globally (except real inputs), suppresses the copy/share/lookup context menu, kills link previews, and turns off bounce/overscroll. Same instinct on the web side via &lt;code&gt;-webkit-tap-highlight-color: transparent&lt;/code&gt; and &lt;code&gt;overscroll-behavior-y: none&lt;/code&gt; — belt and suspenders across the native/web boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera permission for a plain HTML input
&lt;/h2&gt;

&lt;p&gt;The upload flow is a bare &lt;code&gt;&amp;lt;input type="file"&amp;gt;&lt;/code&gt; — the web app has no idea it's in a WebView. But camera capture from a web file picker needs an OS permission that behaves inconsistently if only requested lazily mid-flow. So the shell proactively requests camera/photo permissions once the page loads, ahead of the user ever tapping upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one screen the theming audit never reached
&lt;/h2&gt;

&lt;p&gt;Small confession: the error screen's retry button is a hardcoded &lt;code&gt;#2E7D5B&lt;/code&gt; green. Brand teal everywhere else is &lt;code&gt;#0d9488&lt;/code&gt;. Not the same color — and this is the one screen a 21-page design consolidation pass never touched, because it's native code that only renders when something's already gone wrong.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;Try MyVitals now&lt;/a&gt;&lt;/strong&gt; — same app, same day, web or home screen icon.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>webview</category>
      <category>mobile</category>
      <category>react</category>
    </item>
    <item>
      <title>The Month My AI Pipeline Failed 100% of the Time and Every Log Said "Success"</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Mon, 07 Sep 2026 07:51:00 +0000</pubDate>
      <link>https://dev.to/suyashdev/the-month-my-ai-pipeline-failed-100-of-the-time-and-every-log-said-success-58ba</link>
      <guid>https://dev.to/suyashdev/the-month-my-ai-pipeline-failed-100-of-the-time-and-every-log-said-success-58ba</guid>
      <description>&lt;p&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;MyVitals&lt;/a&gt; extracts lab values with one LLM call, then reconciles raw names against a shared dictionary — exact match, fuzzy match, then an LLM call for the leftovers. If that call fails outright, the pipeline doesn't fail the upload — it degrades: unmatched metrics auto-create a new dictionary entry instead of finding the right one. Good design, on its own.&lt;/p&gt;

&lt;p&gt;Here's the problem: an env var meant for the OCR endpoint got set on the variable that goes to Chat Completions instead. Every metric-matching call, for about a month, hit &lt;code&gt;400 Invalid Model&lt;/code&gt;. Every single one. And because of the graceful degradation above, &lt;strong&gt;every upload still reported success.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why nobody noticed
&lt;/h2&gt;

&lt;p&gt;The visible symptom wasn't an error — it was a canonical-metrics dictionary slowly fragmenting into near-duplicates. Nothing about that looks like a bug from the outside. The metric everyone watches, "did uploads succeed," stayed at 100%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: when a stage is designed to degrade instead of fail loudly, the success of the operation it's embedded in tells you nothing about whether that stage ran. You need a metric for the stage itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually caught it
&lt;/h2&gt;

&lt;p&gt;Not an alert, not a test — there's no integration harness exercising the real pipeline. A routine cost audit noticed the LLM-matching cost line had gone quiet, which prompted someone to actually read the error logs. The diagnosis — &lt;code&gt;400 Invalid Model&lt;/code&gt; — had been sitting in the database the whole time, inside a raw error string, in a tooltip nobody had reason to open.&lt;/p&gt;

&lt;p&gt;The fix wasn't more data, it was structuring what already existed: typed failure classification (error type, HTTP status, retryability) grouped by that classification instead of raw message text. &lt;code&gt;4× · 36% of matching calls · invalid_model&lt;/code&gt; is a bug report. Four chronological stack traces is a wall nobody reads.&lt;/p&gt;

&lt;h2&gt;
  
  
  The retry budget has to know your reverse proxy, personally
&lt;/h2&gt;

&lt;p&gt;Extraction runs synchronously inside the upload request — no job queue yet. Nginx's &lt;code&gt;proxy_read_timeout&lt;/code&gt; is 120s. If retry logic doesn't know that number: three 90-second retries run for 4.5 minutes against a socket Nginx already closed. Client gets a 504, server keeps working on nothing, report sits at &lt;code&gt;"processing"&lt;/code&gt; forever.&lt;/p&gt;

&lt;p&gt;Fix: a shared wall-clock budget (105s, deliberately under 120s) passed through both extraction and matching, so retries stop before the proxy would kill the connection anyway. Retries only happen for genuinely transient failures — a 401 isn't going to succeed on attempt two, and every retry is a real charge. A provider's &lt;code&gt;Retry-After&lt;/code&gt; is honored as sent, not clamped — ignoring a rate limiter's instructions just earns another 429 faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your retry budget and your proxy's timeout are the same constraint wearing two config files.&lt;/strong&gt; Tune only one and you haven't fixed anything — you've just moved where the zombie request dies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Give every "designed to degrade" stage its own visible failure-rate metric.&lt;/li&gt;
&lt;li&gt;Structure error data at write time, not read time — you won't go back and re-parse a month of raw strings later.&lt;/li&gt;
&lt;li&gt;Budget synchronous retries against your actual proxy timeout, explicitly, in the same unit.&lt;/li&gt;
&lt;li&gt;Log the alias &lt;em&gt;and&lt;/em&gt; the resolved concrete model, separately — "it worked yesterday" isn't debuggable if you can't tell whether the model changed underneath you.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;Try MyVitals now&lt;/a&gt;&lt;/strong&gt; — the pipeline now tells on itself when something's wrong.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>monitoring</category>
      <category>node</category>
      <category>security</category>
    </item>
    <item>
      <title>Building "Login As Mom" Without Building a Permissions System</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Sun, 06 Sep 2026 07:50:00 +0000</pubDate>
      <link>https://dev.to/suyashdev/building-login-as-mom-without-building-a-permissions-system-4jcn</link>
      <guid>https://dev.to/suyashdev/building-login-as-mom-without-building-a-permissions-system-4jcn</guid>
      <description>&lt;p&gt;Every app with shared access eventually gets asked for "can my daughter manage my account for me." My instinct was full RBAC. What &lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;MyVitals&lt;/a&gt; actually needed — one person managing a household's lab reports — was closer to "let me act as this person entirely," not granular per-resource permissions. Building it &lt;em&gt;safely&lt;/em&gt; was the interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model: an invite is a membership, not a separate thing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;FamilyMember&lt;/code&gt; is one row per &lt;code&gt;(familyId, invitedEmail)&lt;/code&gt;, representing a pending invite and an accepted membership as the &lt;em&gt;same document&lt;/em&gt; transitioning state. &lt;code&gt;userId&lt;/code&gt; stays &lt;code&gt;null&lt;/code&gt; until the invited email matches an account.&lt;/p&gt;

&lt;p&gt;One detail worth stealing: the invite token is cleared on acceptance via &lt;code&gt;undefined&lt;/code&gt;, not &lt;code&gt;null&lt;/code&gt;. There's a sparse unique index on it, and sparse indexes only exclude &lt;em&gt;absent&lt;/em&gt; fields — &lt;code&gt;null&lt;/code&gt; still counts as a value and collides the moment a second person accepts. One character between "works" and "second invite ever throws a duplicate key error."&lt;/p&gt;

&lt;h2&gt;
  
  
  The permission check is one function, and it is never cached
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;canActAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trueUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetUserId&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;trueUserId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;targetUserId&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;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sharesAcceptedFamilyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trueUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetUserId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// live DB read&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Called on &lt;strong&gt;every request&lt;/strong&gt;, not cached, not memoized. This is the decision I'd defend hardest: cache it and "removing someone revokes access immediately" becomes "...within roughly five minutes." One extra DB read per request buys a security property that's actually true instead of one that's true most of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query param, not header
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;?asUserId=&lt;/code&gt; — because some frontend call sites are plain &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;img src&amp;gt;&lt;/code&gt; tags with no way to attach a custom header. A query param works everywhere a URL works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two identities, one footgun
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;req.effectiveUserId&lt;/code&gt;&lt;/strong&gt; — whose data to read/write. Query by this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;req.actingUserId&lt;/code&gt;&lt;/strong&gt; — who's really making the request, for audit fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using &lt;code&gt;req.userId&lt;/code&gt; directly in a new controller doesn't error — it silently breaks acting-as. A family member switches to their mother's profile, uploads a report, and it lands under the &lt;em&gt;acting&lt;/em&gt; user's own account instead. No warning, just a report filed under the wrong person's medical history. There's no type system catching this (plain ESM JS) — it survives on convention and code review alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this deliberately doesn't do
&lt;/h2&gt;

&lt;p&gt;No granular permissions, no "view but not edit." Symmetric, all-or-nothing, targeting one person managing a household — not a care team with clearance levels. If that ever changes, this model gets replaced, not extended.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;Try MyVitals now&lt;/a&gt;&lt;/strong&gt; — invite a family member and switch profiles in ten seconds.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>security</category>
      <category>api</category>
      <category>node</category>
    </item>
    <item>
      <title>Two Caches, One WebView, and a Deep Distrust of navigator.onLine</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Sat, 05 Sep 2026 07:48:00 +0000</pubDate>
      <link>https://dev.to/suyashdev/two-caches-one-webview-and-a-deep-distrust-of-navigatoronline-3bfp</link>
      <guid>https://dev.to/suyashdev/two-caches-one-webview-and-a-deep-distrust-of-navigatoronline-3bfp</guid>
      <description>&lt;p&gt;MyVitals' mobile presence is a native &lt;code&gt;WebView&lt;/code&gt; pointed at a remote URL — not bundled locally. If the phone loses signal in an elevator, a naive setup just shows nothing, forever, until signal returns. For an app about checking your health data anywhere, that's a bad joke.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer one: a service worker
&lt;/h2&gt;

&lt;p&gt;Workbox precaches the app shell and runtime-caches API responses — standard stuff, &lt;em&gt;if&lt;/em&gt; the service worker reliably registers and persists inside a native WebView, which varies by platform version and isn't something you fully control. So it's layer one, not the whole plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer two: the redundant one that actually saves you
&lt;/h2&gt;

&lt;p&gt;A hand-rolled IndexedDB write-through cache at the axios level. Every successful GET gets written to IndexedDB; a shared &lt;code&gt;useCachedQuery&lt;/code&gt; hook serves from it the instant a request fails instead of showing a spinner into the void:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;idbCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;data&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;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;err&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;err&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;idbCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same data, two storage layers, on purpose. The service worker exists so the app shell loads at all in a WebView that's never had a chance to hit the network first; IndexedDB exists because the service worker might just not be there. A proactive prefetch sweep runs on login/reconnect so the cache is warm &lt;em&gt;before&lt;/em&gt; the user goes offline — the goal is "you can't tell you're offline," not "gracefully handle it."&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;navigator.onLine&lt;/code&gt; will lie to your face
&lt;/h2&gt;

&lt;p&gt;It reports whether the network interface is up, not whether it can reach anything — worse inside a WebView. Connectivity is a real network probe (&lt;code&gt;GET /ping.txt&lt;/code&gt;, uncached), not a property read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writes are where I drew a hard line
&lt;/h2&gt;

&lt;p&gt;Reads work offline. &lt;strong&gt;Writes don't&lt;/strong&gt; — no offline write queue anywhere. Offline uploads/edits fail loudly with an inline message instead of queuing silently. This was deliberate: an offline write queue for a health app means conflict resolution, partial-sync failures, stale-queue edge cases — weeks of work for a single developer. Silent data loss is worse than an honest error, especially with someone's cholesterol on the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug waiting to happen: profile scoping
&lt;/h2&gt;

&lt;p&gt;Both cache layers key on &lt;code&gt;(endpoint, activeProfileId)&lt;/code&gt;, not just the endpoint. MyVitals has family sharing — one login can "act as" a family member. Cache purely by URL and switching profiles means briefly showing your mother's cached dashboard under your session, or leaking yours into hers. If you're building offline support for anything multi-tenant, this is the bug that doesn't show up in your demo.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;Try MyVitals now&lt;/a&gt;&lt;/strong&gt; — load your dashboard, then flip on airplane mode.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>webdev</category>
      <category>react</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Teaching a Dictionary to Learn Instead of Hand-Curating It Forever</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Thu, 03 Sep 2026 19:46:45 +0000</pubDate>
      <link>https://dev.to/suyashdev/teaching-a-dictionary-to-learn-instead-of-hand-curating-it-forever-3pb</link>
      <guid>https://dev.to/suyashdev/teaching-a-dictionary-to-learn-instead-of-hand-curating-it-forever-3pb</guid>
      <description>&lt;p&gt;"Fasting Blood Sugar (FBS)" in mg/dL from Lab A and "Glucose, Fasting" in mmol/L from Lab B, a year apart, are the same measurement. If your app can't figure that out, it can't draw a trend line — which is the entire point of &lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;MyVitals&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four tiers, cheapest first, first match wins
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Exact alias match&lt;/strong&gt; — normalize the raw name, compare against known aliases. Instant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exact match on the extraction model's own guess&lt;/strong&gt; (&lt;code&gt;canonicalNameGuess&lt;/code&gt;) — added after a real bug, below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fuzzy similarity&lt;/strong&gt; (Dice coefficient + token-set comparison) with a hard guard against matching "HDL" to "non-HDL Cholesterol" just because they're close.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM fallback&lt;/strong&gt; — batched, retried, timeboxed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-create&lt;/strong&gt; — mint a new entry. Report still saves. Dictionary just grew instead of getting smarter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whatever tier wins, the raw name gets appended as a new alias. The dictionary &lt;strong&gt;self-improves across every user&lt;/strong&gt; — the fifth report where a lab prints "PCV" for hematocrit, tier 1 catches it instantly. That's the real moat: not "we can read a PDF," but "we get cheaper and more accurate with every report anyone uploads."&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that made two Hematocrits
&lt;/h2&gt;

&lt;p&gt;The model's &lt;code&gt;canonicalNameGuess&lt;/code&gt; used to be used only to &lt;em&gt;name&lt;/em&gt; a new entry, never to &lt;em&gt;find&lt;/em&gt; an existing one. Lab A prints "HCT," Lab B prints "PCV / Haematocrit" — neither raw name matches, fuzzy misses, both fall through to auto-create, and auto-create names both of them "Hematocrit" using the guess. Now you have &lt;code&gt;hematocrit&lt;/code&gt; and &lt;code&gt;hematocrit_1&lt;/code&gt;, splitting one measurement into two trend lines depending on which lab drew your blood — while the model had correctly identified both as Hematocrit the whole time. The pipeline just never asked.&lt;/p&gt;

&lt;p&gt;Tier 2 (checking the guess against the dictionary &lt;em&gt;before&lt;/em&gt; auto-create) fixed it — deliberately exact-only, never fuzzy, because a wrong merge puts two different analytes on one chart with zero indication it happened. That's worse than an extra row. Cleanup merged 14 duplicate groups, 126 → 112 metrics, full backup first, refused to run if any reading would come out worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Units lie in more creative ways than names do
&lt;/h2&gt;

&lt;p&gt;µg/dL (micro sign) and μg/dL (Greek mu) and ug/dL (gave up on Unicode) are one unit in three costumes. The name-matching normalizer strips non-alphanumeric characters, collapsing all three into different strings that then compare as &lt;em&gt;different units&lt;/em&gt; — 15 of 27 "unconvertible" readings turned out to be exactly this: correctly matched data, silently excluded from its own chart over a font rendering difference.&lt;/p&gt;

&lt;p&gt;Fix: a second normalizer, used &lt;strong&gt;only&lt;/strong&gt; for unit comparison, that knows µ/μ/u are the same prefix — and nothing else. It does not get to decide mg/dL ≈ mmol/L, or that μU/mL ≈ μIU/mL (one character apart, not the same unit). Any real equivalence claim needs a human to assert it explicitly. Correctness beats completeness when there's a chart on the other end.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;Try MyVitals now&lt;/a&gt;&lt;/strong&gt; — upload an old report and watch it reconcile into a trend line.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>backend</category>
      <category>datascience</category>
      <category>healthtech</category>
    </item>
    <item>
      <title>I Wired 4 LLM Providers Into One Interface So I'd Never Have to Beg a Single Vendor for Mercy</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Thu, 03 Sep 2026 19:45:03 +0000</pubDate>
      <link>https://dev.to/suyashdev/i-wired-4-llm-providers-into-one-interface-so-id-never-have-to-beg-a-single-vendor-for-mercy-mo4</link>
      <guid>https://dev.to/suyashdev/i-wired-4-llm-providers-into-one-interface-so-id-never-have-to-beg-a-single-vendor-for-mercy-mo4</guid>
      <description>&lt;p&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;MyVitals&lt;/a&gt; reads your lab reports with AI. "AI" here is actually two different jobs wearing a trenchcoat:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extraction&lt;/strong&gt; — read a PDF, pull structured data out, needs strong vision + reliable structured output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat&lt;/strong&gt; — answer "is my TSH bad" fast and cheap, at conversational volume.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bolting both onto one model is how you either overpay for reasoning nobody needed on a "thanks!" message, or starve extraction of the quality it actually needs. So they run on independently swappable providers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mistral        &lt;span class="c"&gt;# extraction + metric matching&lt;/span&gt;
&lt;span class="nv"&gt;CHAT_LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openai    &lt;span class="c"&gt;# chat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swapping either is a &lt;code&gt;.env&lt;/code&gt; edit and a restart. Not a deploy. Not a refactor.&lt;/p&gt;

&lt;h2&gt;
  
  
  One interface, four adapters
&lt;/h2&gt;

&lt;p&gt;Every provider — Gemini, OpenAI, Anthropic, Mistral — implements the same three methods: &lt;code&gt;extractReport&lt;/code&gt;, &lt;code&gt;matchUnmatchedMetrics&lt;/code&gt;, &lt;code&gt;chat&lt;/code&gt;. No controller anywhere talks to a provider SDK directly. Four vendors also means four dialects of "give me JSON back" (&lt;code&gt;responseSchema&lt;/code&gt;, &lt;code&gt;json_schema&lt;/code&gt; strict mode, &lt;code&gt;output_config.format&lt;/code&gt;, OCR annotation format) — normalized once behind a shared schema instead of four copies of prompt text slowly drifting apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two billing models, one surprising economics fact
&lt;/h2&gt;

&lt;p&gt;Mistral's OCR extraction is billed &lt;strong&gt;per page&lt;/strong&gt;. Everything else is billed &lt;strong&gt;per token&lt;/strong&gt;. Which means: a report upload costs roughly the same no matter how chatty your history is, but a chat message gets &lt;em&gt;more expensive the longer you've used the product&lt;/em&gt; — because grounded chat means stuffing your entire metric history into the prompt every turn (no vector DB, deliberately — per-user data is small enough that RAG would solve a problem that doesn't exist yet). Your most retained users are mechanically your most expensive ones. Nobody puts that in the pitch deck.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug: &lt;code&gt;400 Invalid Model&lt;/code&gt;, for a month, silently
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;MISTRAL_MODEL&lt;/code&gt; (goes to Chat Completions, used for metric matching) got set to an OCR-only model name. Every matching call failed with &lt;code&gt;400 Invalid Model&lt;/code&gt; for roughly a month — and nobody noticed, because the pipeline is &lt;em&gt;designed&lt;/em&gt; to degrade: a failed matching call just falls through to auto-creating a new dictionary entry instead of finding the existing one. Every upload still reported success. The only symptom was a canonical-metrics dictionary quietly fragmenting in the background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: if a stage is designed to degrade instead of fail, its failure rate needs its own visible metric — "the operation succeeded" tells you nothing about whether the expensive, accurate path ran at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aliases in, concrete models logged
&lt;/h2&gt;

&lt;p&gt;Env vars hold aliases (&lt;code&gt;mistral-small-latest&lt;/code&gt;) so vendor upgrades land free. But logging the alias into a cost table is useless six months later. So the call goes out with the alias, and a resolver (cached 6h, never throws) logs what it actually resolved to — &lt;code&gt;mistral-small-2603&lt;/code&gt; — alongside the alias. Upgrade for free, keep history that still means something.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://myvitals.co.in" rel="noopener noreferrer"&gt;Try MyVitals now&lt;/a&gt;&lt;/strong&gt; — upload a PDF and watch it get read, matched, and charted.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>node</category>
      <category>architecture</category>
      <category>healthtech</category>
    </item>
    <item>
      <title>How I boosted my App Performance up to 80%</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Mon, 07 Oct 2024 06:35:00 +0000</pubDate>
      <link>https://dev.to/suyashdev/how-i-boosted-my-app-performance-up-to-80-334n</link>
      <guid>https://dev.to/suyashdev/how-i-boosted-my-app-performance-up-to-80-334n</guid>
      <description>&lt;h3&gt;
  
  
  ⌛ Recap Time
&lt;/h3&gt;

&lt;p&gt;In my last blog I talked about how I Reduced my app size from 75MB to 34MB in just 2 weeks ( &lt;a href="https://dev.to/suyashdev/how-i-reduced-my-app-size-from-75mb-to-34mb--51m1"&gt;View !&lt;/a&gt; ). But that's not all , I also improved overall performance of our app upto 80% 🚀.&lt;/p&gt;

&lt;p&gt;Let's discover HOW !!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  🕜 The Lore
&lt;/h2&gt;

&lt;p&gt;After a simple round of walk through I discovered few of the top tier issues in our app leading to bad user experience and performance single headedly. What a day !&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Main Villain - Whole App UI Frozen while generating Realtime response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Side Villain - Slow response time and No frame rates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Villain's lover - Too many Api calls &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Undead Army - Poor Error handling and crashes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sufferings - More CPU usages and Server Costs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Tarnished - ME !&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57dpwy4gm5eazj66pv6f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57dpwy4gm5eazj66pv6f.jpg" alt="Tarnished"&gt;&lt;/a&gt;&lt;br&gt;
Hence a lifeless battle of recreation of universe with a better world hope begins. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Tahiti Plan ( But this time it works )
&lt;/h2&gt;

&lt;p&gt;So I started with tackling the easier problems first as it is easy to ignore the great depression than fighting it on the moment.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. ⚛️ Curse of React
&lt;/h3&gt;

&lt;p&gt;The Wisdom and Curse of ReactJs is states. As we grow older in React we realize that lesser the states more better the application. Hence this particular piece of art was using 22 ( Yes goddamn 22 useStates) in a single chat screen where all you can do is send message and receive message.&lt;/p&gt;

&lt;p&gt;Cherry on the top !&lt;br&gt;
We were using Server Side event implementation for getting chunk-by-chunk data from server , which in case was word-by-word. So if you had a query which has a response of 100 words ( THIS IS LEAST OF RESPONSE ). It will actually receive 100 events.&lt;/p&gt;

&lt;p&gt;So if you know the maths, &lt;strong&gt;100*22 = 2200 re-renders&lt;/strong&gt; each time we get a response.&lt;/p&gt;

&lt;p&gt;Do I have to explain any further ? ( NO )&lt;/p&gt;

&lt;p&gt;So I begin recreating the whole screen and took down the number to 6 states now. With better and smooth functionality as before. &lt;/p&gt;

&lt;p&gt;That is &lt;strong&gt;72% more performant&lt;/strong&gt; that previous !!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. ❄️ The Frozen Desert
&lt;/h2&gt;

&lt;p&gt;Now after witnessing the Radahn of React, we can easily conclude that app is going to be freezing quite a lot right ?&lt;/p&gt;

&lt;p&gt;Now even with 6 states, the main issue remains same it is 100*6. We are still hanging but with less states.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj5fi3b01h9qep14dd6u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj5fi3b01h9qep14dd6u.jpg" alt="Hang with less states"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main cause was, react dom getting updated on each chunk. So to tackle this we used &lt;strong&gt;"Batch Processing &amp;amp; Frame Rates Generation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Hell Yeahh !&lt;/p&gt;

&lt;p&gt;So basically instead updating the DOM each time we get a chunk, we were making batches of chunk and updating it in a fixed dynamic frame rate. These frame rates were called from OS so every device will have a different FPS as per system capacity giving the app more robust and compatible performance.&lt;/p&gt;

&lt;p&gt;We captured a limited set of chunks in a batch and hold the response till the frame is released and repeated the same till all chunks are processed.&lt;/p&gt;

&lt;p&gt;Hence instead of updating DOM 100 times we only updated DOM 3-4 times. &lt;/p&gt;

&lt;p&gt;Now do the maths and calculate the performance enhancement for Homework !&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. 😊 Be a good listener !
&lt;/h2&gt;

&lt;p&gt;It didn't work for me to get a girlfriend, but certainly worked to make the app much better. &lt;/p&gt;

&lt;p&gt;Apis are cool and nice way to get data but using them wisely is a skill of your own ! Now this app was using this api to get the user status from backend. But the best part is it was using it every 3 seconds !!&lt;/p&gt;

&lt;p&gt;I get it, developer had insecurities but this is not what they meant by bringing Work-life balance.&lt;/p&gt;
&lt;h4&gt;
  
  
  a) Fetching
&lt;/h4&gt;

&lt;p&gt;In order to get the user data every time user uses the app, is to make the call at app start or every time app gets called from recent ( App state listener ). Calling it every 3 seconds not only uses Mobile resources into a infinite stream but also cause Server overhead .&lt;/p&gt;

&lt;p&gt;Instead of getting 100 requests from 100 users, serve will get 100 request from 1 user. Doesn't sound very scalable and reliable to me.&lt;/p&gt;

&lt;p&gt;As well as it creates untraceable memory leaks and usages which creates problem in longer usages.&lt;/p&gt;
&lt;h4&gt;
  
  
  b) Data Flow
&lt;/h4&gt;

&lt;p&gt;Now after resolving that inhouse DDOS attack, I discovered that this app was using many apis whose data was getting ghosted in thin air ( Poor data handling ). Instead of caching data and using it again in same flow, the app was calling apis again. &lt;/p&gt;

&lt;p&gt;I made sure data gets cached and flowed linearly to the flow and api is called only when needed for fresh instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Point to remember !&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This resulted in better server health and less downtime for our backend due to too much api requests. As it costs company to run backend it is crucial to use apis effectively and only when needed&lt;/p&gt;

&lt;p&gt;Not only for backend but for frontend as well, making extra api calls make it more system consuming as it has to do more HTTP handshakes and protocols every time you make a call.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. 😎 Its not a Error if we don't acknowledge it !
&lt;/h2&gt;

&lt;p&gt;One of the crucial thing for handling apis is, ERRORS. Consoling them to the logs isnt enough as it makes user's exp far worse than their good usages.&lt;/p&gt;

&lt;p&gt;It is important to handle errors from any action using some kind of feedback system . It can be an Alert or Popup or Toast or anything. But user should know why and how it happened so that they can report it back or atleast get to know what they did wrong !&lt;/p&gt;


&lt;h2&gt;
  
  
  4. 💔 Her Memories
&lt;/h2&gt;

&lt;p&gt;Gottacha homie ! She aint coming back but the memory leaks will. One of the main thing we forget while attaching any listener or Api call is to remove its instance after we close that activity.&lt;/p&gt;

&lt;p&gt;This app had tone of it, api calls were getting called even after activity is closed or in background. Causing unnecessary CPU usage and resource hogging making app more laggy and hard to use.&lt;/p&gt;

&lt;p&gt;Proper cleaning of these makes app more faster and less over heading. &lt;/p&gt;


&lt;h2&gt;
  
  
  5. Declaration of Performance
&lt;/h2&gt;

&lt;p&gt;Now a basic way to use any asset is to import it and use it right ?&lt;/p&gt;

&lt;p&gt;But do you know how it works ? Every time you default import an item it gets allocated into memory with an initialization. So if you import and declare a Image or component in 5 files like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Profile&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;../../profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will create 5 instances of it for the same thing !&lt;/p&gt;

&lt;p&gt;Instead you should call all assets in one index file and import the object from it, that way it will only be declared once and will be used by Reference everywhere.&lt;/p&gt;

&lt;p&gt;Hence reducing the memory usage to 4/5. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Conclusion -
&lt;/h2&gt;

&lt;p&gt;Your a good man Arthor ! ( Sorry I just completed RDR2 and it was a great great game ) . &lt;/p&gt;

&lt;p&gt;With these changes the app performance boosted like hell with not just better mobile side health but as well as better Server side optimization. &lt;/p&gt;

&lt;p&gt;The Store Rating went from 3.5 to 4.1 in just 1 week of using !!!&lt;/p&gt;

&lt;p&gt;Remember it is not just a code but a story on how users interacts with it.&lt;/p&gt;

&lt;p&gt;As a Frontend developer, the whole product depends upon us. No matter how scalable the backend is, the end product which user is going to use is out creation and it is the only thing they make decision on. So it is most important for us to give them a smooth interaction which leads to better business for the entire company.&lt;/p&gt;

&lt;p&gt;🚀 Drop comments if you like the blog, or share it with your homies to let them enjoy it as well !&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>android</category>
      <category>ios</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How I reduced my app size from 75MB to 34MB !!</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Fri, 27 Sep 2024 07:55:59 +0000</pubDate>
      <link>https://dev.to/suyashdev/how-i-reduced-my-app-size-from-75mb-to-34mb--51m1</link>
      <guid>https://dev.to/suyashdev/how-i-reduced-my-app-size-from-75mb-to-34mb--51m1</guid>
      <description>&lt;h2&gt;
  
  
  🕜 The Lore
&lt;/h2&gt;

&lt;p&gt;So recently I was hired by Neurobridge Tech. as a Senior Mobile app developer to develop and lead end-to-end product development of their Flagship app Chanakya AI !&lt;/p&gt;

&lt;p&gt;Wanna checkout the app? &lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=tech.neurobridge.chanakya" rel="noopener noreferrer"&gt;Download Android &lt;/a&gt; &lt;br&gt;
&lt;a href="https://apps.apple.com/us/app/chanakya-ai/id6504797681" rel="noopener noreferrer"&gt;Download iOS&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now they already had the app released and users were using it quite a much. But the app size was around 75mb at that time. So naturally we had some issues with performance, scale, etc but we will discuss that in the next post.&lt;/p&gt;

&lt;p&gt;Back to the lore, now as industry-standard a Simple app without any complex processing at the client side or 30-40 heavy animation screens, the app size should not be more than 25 MB; but as we are using Server side event handling and some advanced features, 35Mb is fine. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flju9oqsef09jsbp993mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flju9oqsef09jsbp993mg.png" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But here we are with a Big Chungas 75MB Asteroid Destroyer !!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Realization....
&lt;/h2&gt;

&lt;p&gt;I started by identifying where we were using spaces. After a good look ( I was traumatized by the code base ) I discovered that the whole app needs to be refactored with better code practices and more optimized manner &lt;br&gt;
(Some things are beyond salvation ) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p1jzkbbi0ond6vudq54.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p1jzkbbi0ond6vudq54.jpg" alt="frustated" width="760" height="570"&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Recreation (But Better)
&lt;/h2&gt;

&lt;p&gt;Hence after getting OCD from the old code base, I started making new architecture while referring to old ones. &lt;/p&gt;

&lt;p&gt;Now here comes the main part -&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. 🛞 Reinventing Wheel
&lt;/h3&gt;

&lt;p&gt;I noticed that previously we made different screens and components for the functionalities which were 80% the same ( Logged-in user and Guest user ) So I started by combining both flows to reduce the code base. &lt;/p&gt;

&lt;p&gt;I deleted over 300 files of code and brought the whole code base to 75% less code ( 1500 lines of code to approx 350 lines ).&lt;/p&gt;

&lt;p&gt;One of the things to always remember is that, if 2 or more modules have the same base functionality of over 70%, it is always better to keep them in a single source while maintaining a conditional execution. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 🖼️ The Collector
&lt;/h3&gt;

&lt;p&gt;As development is a rapid thing in startups, we often forget to delete any unnecessary files or assets that might make our app heavy from shadows. &lt;/p&gt;

&lt;p&gt;I analyzed and modularised whole images and assets and deleted the unused media leading to size reduction while bundling assets. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. ♾️ Domain expansion - NPM Install
&lt;/h3&gt;

&lt;p&gt;As more experienced you get, the more you realize that if it can be done manually then just do it. &lt;/p&gt;

&lt;p&gt;Don't be that guy "Just one more module bro, I can remove it anytime I want"&lt;/p&gt;

&lt;p&gt;Using Node modules for every little thing even when you can do it yourself isn't cool ! This Bad boi had 3.5GB of Node modules in it ( YESS the freaking GigaByte ) ! &lt;/p&gt;

&lt;p&gt;I don't know how it happened, and really not interested to know as well!&lt;/p&gt;

&lt;p&gt;All I cared about was reducing it to minimal while recreating most of the functionalities and removing unused linked modules as native linked modules get bundled even if they are not used in JS code.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. 🦚 Geeta Method - The Single Source of Truth
&lt;/h3&gt;

&lt;p&gt;Often while developing a complex and interlinked application, we forget to make it modular and more globalized.&lt;/p&gt;

&lt;p&gt;Previously we were using all values, methods, functions, etc by hardcoding them directly in place, which led to extra compilation and memory usage. Leading to a bad product.&lt;/p&gt;

&lt;p&gt;I Modularized every reusable item ( variables, strings, functions, data handlers, etc ) to make sure everything gets initialized only once and then can be used by reference.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

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

&lt;p&gt;With all this refactoring and carefully crafted code in 2 weeks, we were finally able to reduce the app size from 75MB to 34MB in stores. &lt;/p&gt;

&lt;p&gt;A Smaller app not only runs faster but plays a crucial role in user traffic. Nobody wants a Big Chungus app with a slow process, everyone likes to keep it small, fast, and quick. &lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎁 Bonus Content ( Cause why not )
&lt;/h2&gt;

&lt;p&gt;While keeping the app size at best, I also made the whole app 🚀 80% faster in performance and reduced the Network request down to 50% ultimately leading to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better server health&lt;/li&gt;
&lt;li&gt;Less Loadings&lt;/li&gt;
&lt;li&gt;Less Overheads&lt;/li&gt;
&lt;li&gt;Less downtime&lt;/li&gt;
&lt;li&gt;Less running cost&lt;/li&gt;
&lt;li&gt;Scalability stonks&lt;/li&gt;
&lt;li&gt;Low Latency&lt;/li&gt;
&lt;li&gt;Fast UI/UX Flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds Cool right !?&lt;br&gt;
Check out my next post to see how what I exactly used to make the system 80% efficient while keeping size and deps minimal!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/suyashdev/how-i-boosted-my-app-performance-up-to-80-334n"&gt;Click here&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks for Reading my Homies!
&lt;/h3&gt;

&lt;p&gt;Show some love in a comment or ask anything you like :)&lt;/p&gt;

&lt;p&gt;👋 Until Next time!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>android</category>
    </item>
    <item>
      <title>How to Send Data while Navigating Back in React Native</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Mon, 30 Jan 2023 18:20:20 +0000</pubDate>
      <link>https://dev.to/suyashdev/how-to-send-data-while-navigating-back-in-react-native-17dj</link>
      <guid>https://dev.to/suyashdev/how-to-send-data-while-navigating-back-in-react-native-17dj</guid>
      <description>&lt;p&gt;It is one of the most common issues in Mobile apps in React Native. We can send data from ScreenA to ScreenB in params but can't send data from ScreenB to ScreenA while navigating back!&lt;/p&gt;

&lt;h2&gt;
  
  
  But I have got a Hack!
&lt;/h2&gt;

&lt;p&gt;In this blog, I am gonna tell you how to send data from ScreenB to ScreenA while navigating back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's start by making Screen A
&lt;/h3&gt;

&lt;p&gt;In ScreeA, I created a button to navigate to ScreenB with no data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F313fm0friki5fs9ocozz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F313fm0friki5fs9ocozz.png" alt="ScreenA" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Screen B
&lt;/h3&gt;

&lt;p&gt;Now in ScreenB let's make a similar button for going back, but instead of using &lt;code&gt;navigation.goBack()&lt;/code&gt; we will use &lt;code&gt;navigation.navigate()&lt;/code&gt; here.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reason&lt;/strong&gt; - In &lt;code&gt;navigation.navigate()&lt;/code&gt; function, If the given path is present in the navigation tree, it will navigate to that path instead of creating a new one, else It will create a new path.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
And as we know, ScreenA was already there in our navigation tree so &lt;code&gt;navigation.navigate()&lt;/code&gt; will move to ScreenA which is technically our previous screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcywncp6cavun6pocp3kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcywncp6cavun6pocp3kp.png" alt="ScreenB" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you might notice here, that the arguments are different from regular ones. Let me explain-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt; - Screen/Route Name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;data&lt;/strong&gt; - data to be passed in routes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;merge&lt;/strong&gt; -
true if you want to merge the data with the given screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, we can &lt;strong&gt;send data to ScreenA&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to handle the new data in Screen A?
&lt;/h2&gt;

&lt;p&gt;When we initialised the screen we didn’t mention any routes params data because there weren't any!&lt;br&gt;
So how are we going to handle this new data in Screen A?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvj593v4gqhgkq93vxzrv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvj593v4gqhgkq93vxzrv.png" alt="Code to handle data from ScreenB to ScreenA" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In ScreenA we will place a useEffect for new route data with a " ? " to check if the data key exists. Initially, the data key wouldn’t exist hence it will do nothing, but after navigating back from ScreenB it will get engaged and log the new data.&lt;/p&gt;

&lt;p&gt;Basically we are forcing new route data into our ScreenA.&lt;/p&gt;

&lt;p&gt;And POOF, we have our data from ScreenB!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for Reading !&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>blockchain</category>
      <category>web3</category>
      <category>offers</category>
    </item>
    <item>
      <title>React States works by Reference</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Mon, 30 Jan 2023 09:12:59 +0000</pubDate>
      <link>https://dev.to/suyashdev/react-states-works-by-reference-58ae</link>
      <guid>https://dev.to/suyashdev/react-states-works-by-reference-58ae</guid>
      <description>&lt;p&gt;Today I learned something cool in React. I was trying to update a post in the list of Posts ( State ) but even after changing the element's key value, it wasn't reflecting in UI ( but showing updated data in the console log. I spent hours trying to figure out why it is happening and according to JS, I was doing the right array manipulation.&lt;/p&gt;

&lt;p&gt;So I did some research and a GitHub thread finally guided me to the right track, comes out that the React States are used by references not by value.&lt;/p&gt;

&lt;p&gt;"React compares by reference, in the setState(newState) call, you are just setting the state to the same list. Changing the contents of the list doesn't change the reference to the list. When the next state is the same as the old state, React bails out on doing any work.&lt;br&gt;
One quick thing you can do is slice the array like this:&lt;/p&gt;

&lt;p&gt;const newData = oldData.slice(0);&lt;br&gt;
newData[0] = 'something'&lt;br&gt;
setState(newData);&lt;br&gt;
"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vercel/next.js/discussions/32802#discussioncomment-2652014"&gt;GitHub Thread&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here slice() returns a new array based on the given condition, so it breaks the state reference and creates a new array reference. Now React will take the new array as a different entity and will update the state.&lt;/p&gt;

&lt;p&gt;React is a beautiful thing ❤️&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to show Loading wrapper in ReactJS / React Native while api call !</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Thu, 27 Oct 2022 21:17:50 +0000</pubDate>
      <link>https://dev.to/suyashdev/how-to-show-loading-wrapper-in-reactjs-react-native-while-api-call--26oe</link>
      <guid>https://dev.to/suyashdev/how-to-show-loading-wrapper-in-reactjs-react-native-while-api-call--26oe</guid>
      <description>&lt;p&gt;No Introduction, Let's cut to the chase&lt;/p&gt;

&lt;p&gt;You have an API and a component to show with data provided by API. Now the problem is, that component gets called before the API call is completed resulting in throwing an undefined or null error while calling children keys in a component.&lt;/p&gt;

&lt;p&gt;To Resolve this we use something called a Loading Wrapper. Now, this method works on both React and React Native as it uses common useState and Reacts LifeCycles to work.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Maintaining a Loading State
&lt;/h2&gt;

&lt;p&gt;Let's start by making a loading state to check and update our application whenever the loading starts and ends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we will update it to &lt;code&gt;true&lt;/code&gt; when the call starts and &lt;code&gt;false&lt;/code&gt; when the call ends.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Calling APi with Loading State
&lt;/h2&gt;

&lt;p&gt;In this step, we will simply update the &lt;code&gt;isLoading&lt;/code&gt; state to true and false to tell our application the current loading condition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;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;getData&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;What the hell did you do here ????????&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well I started by setting &lt;code&gt;isLoading&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; when our API call started ( just before Axios) and then to &lt;code&gt;false&lt;/code&gt; when our promise finally ended ( either with success or failure )&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Showing Loading wrapper based on this api call
&lt;/h2&gt;

&lt;p&gt;Now our application knows if the API is loading or not, let's move to the rendering part.&lt;/p&gt;

&lt;p&gt;We will use conditional rendering to render the diff UI based on diff cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
      &lt;span class="nx"&gt;data&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YourComponent&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Can&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t connect to server ! &amp;lt;/h1&amp;gt;
   :
   &amp;lt;span&amp;gt; Loading... &amp;lt;/span&amp;gt;
)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are first checking is &lt;code&gt;isLoading&lt;/code&gt; is false, which means the API call has ended. So we will move to render our component. If &lt;code&gt;isLoading&lt;/code&gt; is true it will show a &lt;code&gt;span&lt;/code&gt; tag with text as Loading...&lt;/p&gt;

&lt;p&gt;Then, we are checking if &lt;code&gt;data!==null&lt;/code&gt; which means the API call has been success full and populated with backend data. If it is null that means the API call is failed and there is some error in the API call.&lt;/p&gt;

&lt;p&gt;It is not really a part of Loading Wrapper but it is most commonly used with loading states to avoid crashes and undefined errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So Now our loading wrapper is ready, and each time the &lt;code&gt;getData()&lt;/code&gt; function gets called it will again trigger the loading and our render function will act accordingly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  ❤️🧑🏻‍💻Thanks for reading , If you liked this blog please drop a like and comment !
&lt;/h3&gt;

</description>
    </item>
    <item>
      <title>Looking for open source contributors in React Native !</title>
      <dc:creator>Suyash Vashishtha</dc:creator>
      <pubDate>Mon, 17 Oct 2022 10:47:34 +0000</pubDate>
      <link>https://dev.to/suyashdev/looking-for-open-source-contributors-in-react-native--l7m</link>
      <guid>https://dev.to/suyashdev/looking-for-open-source-contributors-in-react-native--l7m</guid>
      <description>&lt;p&gt;I am looking for open-source contributors to work with me on my cute little UI Kit for react-native. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;🙋🏻‍♂️ Hi, I am Suyash. I am React Native Developer from India and working on a small-scale UI Kit for react native. &lt;/p&gt;

&lt;p&gt;I aim to provide some miscellaneous Ui elements that are either ugly or not available in react native default element collection. A common example is Alert [ Ugly AF in the android system ]. &lt;/p&gt;

&lt;h3&gt;
  
  
  So why would you use my UI KIT when others are available huh?
&lt;/h3&gt;

&lt;p&gt;Well, the answer is, I am trying to make all these elements without using any third library or dev dependencies so the support line would be maximum and you don't have to install some other stuff that u will never see in the whole dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to participate
&lt;/h2&gt;

&lt;p&gt;Note - Use the given theme or add the colors if u think that would look cool, but don't change the previous colors.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Fork The Repo from &lt;a href="https://github.com/suyashvash/protonic-ui"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start developing something&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Submit a PR with a proper description of what your magical ✨ div ✨ does and also include the screenshots ( Gotta check the aesthetic ).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If everything goes right, I will merge them asap.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Don't have an Ideas right now ?
&lt;/h3&gt;

&lt;p&gt;I gotta you, try to make these -&lt;br&gt;
     1. Alert Pop up ( Done )&lt;br&gt;
     2. Vertically scrollable tabs with onScroll tab Changing&lt;br&gt;
     3. TextInputs&lt;br&gt;
     4. Dropdown&lt;/p&gt;

&lt;h3&gt;
  
  
  Either way, you are always welcome to use the KIT, provide review or have a nice talk about it ☕️
&lt;/h3&gt;

</description>
      <category>reactnative</category>
      <category>opensource</category>
      <category>contributorswanted</category>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
