<?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: running squirrel</title>
    <description>The latest articles on DEV Community by running squirrel (@running_squirrel).</description>
    <link>https://dev.to/running_squirrel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2519384%2F5e4a9b9f-40a2-44c0-98f3-cef20f69118b.png</url>
      <title>DEV Community: running squirrel</title>
      <link>https://dev.to/running_squirrel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/running_squirrel"/>
    <language>en</language>
    <item>
      <title>Offline React Native Apps: How to Cache Files That Must Open Without Network</title>
      <dc:creator>running squirrel</dc:creator>
      <pubDate>Sat, 25 Apr 2026 09:41:36 +0000</pubDate>
      <link>https://dev.to/running_squirrel/offline-react-native-apps-how-to-cache-files-that-must-open-without-network-1ahn</link>
      <guid>https://dev.to/running_squirrel/offline-react-native-apps-how-to-cache-files-that-must-open-without-network-1ahn</guid>
      <description>&lt;p&gt;If you search for “offline React Native,” you will find a lot of guidance about images, lists, and optimistic UI. That is useful, but it often misses the assets that actually stop work in the field: &lt;strong&gt;PDFs, JSON manifests, small binaries, audio clips&lt;/strong&gt;, and other HTTP-hosted files your app must open &lt;em&gt;right now&lt;/em&gt;, even when connectivity is unreliable.&lt;/p&gt;

&lt;p&gt;One of the best libraries for that specific “cache downloads to disk, open them later” capability is &lt;a href="https://github.com/ifeoluwak/react-native-nitro-cache" rel="noopener noreferrer"&gt;&lt;code&gt;react-native-nitro-cache&lt;/code&gt;&lt;/a&gt; with it's simplistic api anyone can use easily.&lt;/p&gt;

&lt;p&gt;This post is about that second category: file caching for offline-capable React Native apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why “offline React Native” advice often skips the hard part
&lt;/h2&gt;

&lt;p&gt;Most offline guidance optimizes what users &lt;em&gt;see immediately&lt;/em&gt;: scrolling, perceived speed, optimistic updates. That matters, but field workflows also depend on what users can &lt;em&gt;open from storage&lt;/em&gt; when the network disappears.&lt;/p&gt;

&lt;p&gt;Operational apps tend to fail for file reasons, not layout reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;PDF checklist&lt;/strong&gt; did not download before the technician walked into a basement&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;rules manifest&lt;/strong&gt; is stale after a midnight policy change&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;small binary&lt;/strong&gt; or &lt;strong&gt;audio instruction&lt;/strong&gt; is missing when the user is already offline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you want in those situations is not a prettier loading state. You want a &lt;strong&gt;predictable HTTP file cache&lt;/strong&gt; with explicit freshness and cleanup tools.&lt;/p&gt;

&lt;p&gt;That is the shape of problem a file cache is meant to solve: downloads you can treat as &lt;strong&gt;local files&lt;/strong&gt;, with &lt;strong&gt;TTL&lt;/strong&gt;, &lt;strong&gt;forced refresh&lt;/strong&gt;, and simple ways to &lt;strong&gt;inspect and clean up&lt;/strong&gt; what is on disk—so your app can open operational assets offline, not only render UI faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The offline-first file workflow
&lt;/h2&gt;

&lt;p&gt;Think in layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prefetch the critical path&lt;/strong&gt; while the user still has good connectivity (login, sync screen, “prepare for today” action).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serve from disk&lt;/strong&gt; during the session using stable local file paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revalidate on a schedule&lt;/strong&gt; using TTLs that match how often each asset class changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Force refresh&lt;/strong&gt; when the server says “this version is invalid” (feature flags, emergency policy updates).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observe and prune&lt;/strong&gt; using cache stats/entries so support and QA can reason about what is on-device.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This maps cleanly to the &lt;a href="https://github.com/ifeoluwak/react-native-nitro-cache" rel="noopener noreferrer"&gt;&lt;code&gt;react-native-nitro-cache&lt;/code&gt;&lt;/a&gt; primitives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getOrFetch(url, options?)&lt;/code&gt; — return a valid cached file or download it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get(url)&lt;/code&gt; — read-through without downloading&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;has(url)&lt;/code&gt; — fast synchronous membership check against the in-memory index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getBuffer(url)&lt;/code&gt; — read bytes into an &lt;code&gt;ArrayBuffer&lt;/code&gt; for small in-memory consumers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;remove(url)&lt;/code&gt; / &lt;code&gt;clear()&lt;/code&gt; — targeted invalidation vs nuclear reset&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getStats()&lt;/code&gt; / &lt;code&gt;getEntries()&lt;/code&gt; — operational visibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: different TTLs for different file classes
&lt;/h2&gt;

&lt;p&gt;In real apps, “freshness” is not one number. Treat manifests, templates, and media 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rnNitroCache&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-nitro-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cacheManifest&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="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="c1"&gt;// Changes frequently: short TTL 10mins&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rnNitroCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrFetch&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&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;cachePdfTemplate&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="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="c1"&gt;// Changes rarely: longer TTL 7days&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rnNitroCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrFetch&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;7&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;When an entry is returned, you typically care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;url&lt;/code&gt;&lt;/strong&gt;: absolute on-disk path you can hand to viewers/players&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;contentType&lt;/code&gt;&lt;/strong&gt;: useful for routing and validation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;size&lt;/code&gt;&lt;/strong&gt;: useful for UI and telemetry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;expiresAt&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;0&lt;/code&gt; if the entry has no TTL; otherwise the expiry instant in &lt;strong&gt;milliseconds since epoch&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: parse cached JSON without inventing a parallel storage system
&lt;/h2&gt;

&lt;p&gt;For small JSON blobs, &lt;code&gt;getBuffer&lt;/code&gt; can be convenient if your consumer wants bytes in JS.&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;rnNitroCache&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-nitro-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;readCachedJson&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="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;buf&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;rnNitroCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBuffer&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;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;buf&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&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;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&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="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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;unknown&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;
  
  
  Invalidation that matches real product events
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Offline support is not only “store more.” It is also “remove the right things at the right time.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Common triggers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User logs out&lt;/strong&gt; → &lt;code&gt;clear()&lt;/code&gt; if your policy requires wiping cached HTTP assets from the device&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tenant/workspace switch&lt;/strong&gt; → &lt;code&gt;clear()&lt;/code&gt; or selective &lt;code&gt;remove(url)&lt;/code&gt; for tenant-scoped URLs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server publishes a new bundle version&lt;/strong&gt; → &lt;code&gt;getOrFetch(url, { forceRefresh: true })&lt;/code&gt; for the entry points that must update immediately&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Observability: treat the cache as part of your release story
&lt;/h2&gt;

&lt;p&gt;If you have ever debugged “it works on Wi‑Fi,” you know the missing ingredient is visibility.&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;rnNitroCache&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-nitro-cache&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;stats&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;rnNitroCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStats&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;cache entries:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalEntries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bytes:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalSize&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;entries&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;rnNitroCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&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;entries&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;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&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 valuable for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;QA scripts (“did we prefetch the manifest?”)&lt;/li&gt;
&lt;li&gt;internal diagnostics screens&lt;/li&gt;
&lt;li&gt;coarse “disk budget” warnings before downloads&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation and platform reality (so your readers do not get stuck)
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What I would emphasize in a Medium conclusion
&lt;/h2&gt;

&lt;p&gt;Offline React Native is getting more attention because teams are shipping more serious mobile workflows. But it is not just "more caching", it is &lt;strong&gt;the right kind of caching&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;operational files you can open from disk under poor connectivity&lt;/li&gt;
&lt;li&gt;explicit freshness (TTL) and forced refresh paths&lt;/li&gt;
&lt;li&gt;disk-first retrieval for large assets&lt;/li&gt;
&lt;li&gt;targeted invalidation and introspection APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If your roadmap includes offline inspections, offline forms, offline training content, or any “must open on-site” PDFs and manifests, a general-purpose file cache belongs in your architecture review alongside your sync and persistence strategy.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Repo link
&lt;/h2&gt;

&lt;p&gt;To learn more about the library checkout it's repository on &lt;a href="https://github.com/ifeoluwak/react-native-nitro-cache" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>offline</category>
      <category>mobile</category>
      <category>network</category>
    </item>
    <item>
      <title>Top 4 React Native Image Caching Libraries in 2026</title>
      <dc:creator>running squirrel</dc:creator>
      <pubDate>Wed, 22 Apr 2026 20:09:14 +0000</pubDate>
      <link>https://dev.to/running_squirrel/top-4-react-native-image-caching-libraries-in-2026-22n1</link>
      <guid>https://dev.to/running_squirrel/top-4-react-native-image-caching-libraries-in-2026-22n1</guid>
      <description>&lt;p&gt;An opinionated guide to image caching in React Native, from battle-tested classics to the blazing-fast newcomer built for the New Architecture.&lt;/p&gt;

&lt;p&gt;Caching images in React Native has always been painful. The default &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; component is slow, flickers on reloads, and offers almost zero control.&lt;br&gt;
For years developers have relied on a handful of libraries but most of them were built before the New Architecture, before Turbo Modules or Nitro Modules, and before apps started demanding smooth video caching and zero-copy performance.&lt;/p&gt;

&lt;p&gt;In 2026, the game has changed. Here are the Top 4 image caching libraries I recommend today, ranked by real-world usage, performance, and developer experience.&lt;br&gt;
Make sure you check out the last one!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/react-native-fast-image" rel="noopener noreferrer"&gt;react-native-fast-image&lt;/a&gt;&lt;/strong&gt; - The Veteran King (Still Dominant)&lt;/p&gt;

&lt;p&gt;The library is no longer actively maintained but still being used by many. I strongly recommend the fork - &lt;a href="https://www.npmjs.com/package/@d11/react-native-fast-image" rel="noopener noreferrer"&gt;@d11/react-native-fast-image&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Battle-tested for years&lt;/li&gt;
&lt;li&gt;Excellent image prioritization and cache control&lt;/li&gt;
&lt;li&gt;Huge community&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;New Architecture support is patchy (community fork required)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Higher bridge overhead compared to modern Nitro solutions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still the go-to for many production apps, but it's starting to show its age.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/expo-image" rel="noopener noreferrer"&gt;expo-image&lt;/a&gt;&lt;/strong&gt; - The Expo Ecosystem Favorite&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beautiful API and great DX&lt;/li&gt;
&lt;li&gt;Excellent New Architecture support&lt;/li&gt;
&lt;li&gt;Built-in memory + disk caching with cachePolicy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tied to the Expo ecosystem (less ideal for bare React Native)&lt;/li&gt;
&lt;li&gt;Limited programmatic control (no easy remove(url) or cache inspection)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect if you're already in Expo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/react-native-turbo-image" rel="noopener noreferrer"&gt;&lt;strong&gt;react-native-turbo-image&lt;/strong&gt;&lt;/a&gt; - The Modern Native Contender&lt;/p&gt;

&lt;p&gt;Built on Nuke (iOS) and Coil (Android), this library delivers excellent native performance and is gaining traction fast.&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very fast native image loading&lt;/li&gt;
&lt;li&gt;Good New Architecture compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller community than fast-image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A strong option if you want native speed without Nitro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/react-native-nitro-cache" rel="noopener noreferrer"&gt;&lt;strong&gt;react-native-nitro-cache&lt;/strong&gt;&lt;/a&gt; - The Newcomer That's Stealing the Show&lt;/p&gt;

&lt;p&gt;This is the one I'm most excited about in 2026.&lt;br&gt;
Built from the ground up with Nitro Modules + C++, react-native-nitro-cache is a unified asset cache for images, videos, and any binary files. Has a very simple api interface, very easy to use.&lt;/p&gt;

&lt;p&gt;Why it stands out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unified caching (images + videos + arbitrary files)&lt;/li&gt;
&lt;li&gt;Zero-copy ArrayBuffer support for raw binary data&lt;/li&gt;
&lt;li&gt;Blazing-fast in-memory retrieval with safe atomic persistence&lt;/li&gt;
&lt;li&gt;Built-in TTL, programmatic remove(url) and cache inspection&lt;/li&gt;
&lt;li&gt;Full New Architecture support out of the box&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It feels like someone finally built the cache library we've all been waiting for since the New Architecture landed.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;react-native-fast-image&lt;/strong&gt; and &lt;strong&gt;expo-image&lt;/strong&gt; are still solid choices, they are battle tested and the community love them.&lt;/p&gt;

&lt;p&gt;My 2026 recommendation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expo-heavy project → stick with expo-image&lt;/li&gt;
&lt;li&gt;Need maximum battle-tested stability → react-native-fast-image (with the community fork)&lt;/li&gt;
&lt;li&gt;Want the future of unified, high-performance caching → try &lt;a href="https://www.npmjs.com/package/react-native-nitro-cache" rel="noopener noreferrer"&gt;react-native-nitro-cache&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The library is brand new, actively developed, and already solving real pain points that the older solutions never addressed.&lt;br&gt;
Have you tried it yet? Drop a comment below with your current caching setup. I'd love to hear what's working (or not working) for you in 2026.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>react</category>
      <category>performance</category>
    </item>
    <item>
      <title>Why Mobile Apps Deserve Their Own CMS</title>
      <dc:creator>running squirrel</dc:creator>
      <pubDate>Wed, 20 Aug 2025 04:16:50 +0000</pubDate>
      <link>https://dev.to/running_squirrel/why-mobile-apps-deserve-their-own-cms-311f</link>
      <guid>https://dev.to/running_squirrel/why-mobile-apps-deserve-their-own-cms-311f</guid>
      <description>&lt;p&gt;Every website has a CMS. WordPress, Shopify, Contentful — platforms that make content management simple and instant.&lt;br&gt;
But mobile apps? Still waiting days for app store approvals just to fix a typo.&lt;/p&gt;

&lt;p&gt;Why do apps lack the same content management flexibility as websites?&lt;br&gt;
Because app stores were built for static releases, not agile content updates.&lt;/p&gt;

&lt;p&gt;Product managers, marketers, and even compliance teams often need quick updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Change a banner for a flash sale&lt;/li&gt;
&lt;li&gt; Update legal disclaimers&lt;/li&gt;
&lt;li&gt; Fix onboarding text&lt;/li&gt;
&lt;li&gt; Roll out seasonal content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these should require a rebuild.&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%2F33j1wnnvilr0m4l0tuxq.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%2F33j1wnnvilr0m4l0tuxq.png" alt="Resyncbase Visual Editor" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ResyncBase is filling this gap: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built for React Native apps&lt;/li&gt;
&lt;li&gt;Instant content updates&lt;/li&gt;
&lt;li&gt;Live previews on iOS &amp;amp; Android&lt;/li&gt;
&lt;li&gt;Version history &amp;amp; rollback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Benefit Beyond Speed? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empower non-developers to make changes&lt;/li&gt;
&lt;li&gt;Reduce developer distraction&lt;/li&gt;
&lt;li&gt;Keep users happy with bug-free, up-to-date content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just as websites couldn’t scale without CMS platforms, mobile apps can’t stay competitive with app store delays.&lt;br&gt;
It’s time for a CMS for apps.&lt;/p&gt;

&lt;p&gt;Join the ResyncBase waitlist now at &lt;a href="http://www.resyncbase.com" rel="noopener noreferrer"&gt;www.resyncbase.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>reactnative</category>
      <category>product</category>
      <category>mobile</category>
    </item>
    <item>
      <title>How to Add a Vertical Timeline To your React Native App</title>
      <dc:creator>running squirrel</dc:creator>
      <pubDate>Fri, 07 Mar 2025 07:24:58 +0000</pubDate>
      <link>https://dev.to/running_squirrel/how-to-add-a-vertical-timeline-to-your-react-native-app-5afn</link>
      <guid>https://dev.to/running_squirrel/how-to-add-a-vertical-timeline-to-your-react-native-app-5afn</guid>
      <description>&lt;p&gt;To add a component to show the progress/timeline of a process with different statuses, you can use the library &lt;a href="https://www.npmjs.com/package/react-native-vertical-status-progress" rel="noopener noreferrer"&gt;react-native-vertical-status-progress&lt;/a&gt;. Works with Expo and React Native.&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%2F4p0nw6dh8bu0y89sx88v.jpg" 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%2F4p0nw6dh8bu0y89sx88v.jpg" alt="A Timeline of status progress" width="774" height="666"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The  component from the library is designed to visually represent the progress of a multi-step process. Each step is represented by a status indicator that can be customized to show whether the step is completed or pending. This component is ideal for workflows, onboarding processes, or any scenario where you need to display progress through a series of steps. It is compatible with both Expo and React Native projects, making it versatile and easy to integrate into your existing applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Accordion Support: Each status can be expanded or collapsed to show more details. This is useful for providing additional information or actions related to each step.
Customizable Content: You can render any component within the accordion, including call-to-action (CTA) buttons, forms, or any other React Native components.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install react-native-vertical-status-progress&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { VerticalStatusProgress } from 'react-native-vertical-status-progress';

const statuses = [
  {
    title: 'Sign Up Complete',
    subtitle: 'You have successfully signed up.',
    status: 'registered',
  },
  {
    title: 'Set up your account',
    subtitle: 'Add your account details to get started.',
    renderContent: (
      &amp;lt;TouchableOpacity&amp;gt;
        &amp;lt;Text&amp;gt;vbireuvgbireubgireuf&amp;lt;/Text&amp;gt;
      &amp;lt;/TouchableOpacity&amp;gt;
    ),
    status: 'setting_up',
  },
  {
    title: 'Account Verification',
    subtitle: 'We are verifying your account.',
    renderContent: (
      &amp;lt;View&amp;gt;
        &amp;lt;Text&amp;gt;
          We will contact you shortly if we need any additional information.
          Please contact us if you have any questions. Check your email for
          updates.
        &amp;lt;/Text&amp;gt;
        &amp;lt;TouchableOpacity
          style={{
            backgroundColor: colors.ACCENT_BLUE,
            padding: 10,
            borderRadius: 5,
            width: 150,
            alignItems: 'center',
            marginTop: 10,
          }}
        &amp;gt;
          &amp;lt;Text style={{ color: '#fff' }}&amp;gt;Resend Email&amp;lt;/Text&amp;gt;
        &amp;lt;/TouchableOpacity&amp;gt;
      &amp;lt;/View&amp;gt;
    ),
    status: 'verifying',
  },
  {
    title: 'Account Verified',
    subtitle: 'Your account has been verified.',
    status: 'waiting',
  },
  {
    title: 'All Set!',
    subtitle:
      "You're all set up and ready to go. Start using your account now.",
    renderContent: (
      &amp;lt;View&amp;gt;
        &amp;lt;Text&amp;gt;
          Lorem ipsum dolor sit, amet consectetur adipisicing elit. A ullam
          assumenda obcaecati? Minima libero vitae ducimus, omnis, excepturi
          saepe, doloribus corrupti hic deleniti id iure? Qui consequuntur at
          magnam consequatur!
        &amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
    ),
    status: 'ready',
  },
];

const App = () =&amp;gt; {
    return (
        &amp;lt;VerticalStatusProgress statuses={statuses} /&amp;gt;
    );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Customization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can customize the appearance of the react-native-vertical-status-progress component by passing in custom styles and render functions. Here are some examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Custom Ball Component&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const renderCustomBall = (label, idx, isPrev, isFuture) =&amp;gt; (
  &amp;lt;View style={{ backgroundColor: isPrev ? 'blue' : 'grey', width: 16, height: 16, alignItems: 'center', justifyContent: 'center', borderRadius: 4 }}&amp;gt;
    &amp;lt;Text style={{ color: 'white', fontSize: 10 }}&amp;gt;{idx}&amp;lt;/Text&amp;gt;
  &amp;lt;/View&amp;gt;
);

&amp;lt;VerticalStatusProgress
  statuses={statuses}
  renderBall={renderCustomBall}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Custom Stick Component&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const renderCustomStick = (label, idx, isPrev, isFuture) =&amp;gt; (
  &amp;lt;View style={{ flex: 1, width: 5, backgroundColor: isPrev ? 'blue' : 'grey' }} /&amp;gt;
);

&amp;lt;VerticalStatusProgress
  statuses={statuses}
  renderStick={renderCustomStick}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Custom Chevron Component&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const renderCustomChevron = (open, index) =&amp;gt; (
  &amp;lt;Text&amp;gt;{open ? '-' : '+'}&amp;lt;/Text&amp;gt;
);

&amp;lt;VerticalStatusProgress
  statuses={statuses}
  renderChevron={renderCustomChevron}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With react-native-vertical-status-progress it becomes very easy to add any timeline for status progress on your app.&lt;/p&gt;

&lt;p&gt;To see more details about customisation, props and example, visit the library page on npm or github.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>typescript</category>
      <category>expojs</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>How to Generate Types from Your Api Responses in Realtime in Typescript</title>
      <dc:creator>running squirrel</dc:creator>
      <pubDate>Wed, 04 Dec 2024 11:16:35 +0000</pubDate>
      <link>https://dev.to/running_squirrel/how-to-generate-types-from-your-api-responses-in-realtime-in-typescript-2m1i</link>
      <guid>https://dev.to/running_squirrel/how-to-generate-types-from-your-api-responses-in-realtime-in-typescript-2m1i</guid>
      <description>&lt;p&gt;I have always felt a bit annoyed whenever I’m working on a project and I have to add types to an api response.&lt;/p&gt;

&lt;p&gt;The process usually goes like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write a function to fetch data&lt;/li&gt;
&lt;li&gt;call the function on a component or page&lt;/li&gt;
&lt;li&gt;either log the response or inspect the network tab to view the response
&lt;/li&gt;
&lt;li&gt;copy this response, create a new file and paste the response&lt;/li&gt;
&lt;li&gt;start editing the response to create a new type or interface&lt;/li&gt;
&lt;li&gt;import the new type to the function file and set it’s return type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This had been going on for a while and then I thought to find a way to automate it.&lt;/p&gt;

&lt;p&gt;This led to my discovery of a few libraries that can generate types. Unfortunately they were not convenient to work with because they were not generating the types effortlessly and in realtime. They required a lot of manual process as well. I wanted something I could just plug in and be done with and continue with my normal development flow.&lt;/p&gt;

&lt;p&gt;So I decided to build a library that will automate this process for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  realtime-api-types
&lt;/h2&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%2Ft2k2x3ujtaxsdj3g9psv.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%2Ft2k2x3ujtaxsdj3g9psv.png" alt="Generation Service running" width="800" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The aim of this library is to take the pain away from trying to add types from your api responses.&lt;/p&gt;

&lt;p&gt;Find out more on: &lt;a href="https://www.npmjs.com/package/realtime-api-types" rel="noopener noreferrer"&gt;npm&lt;/a&gt; or &lt;a href="https://github.com/ifeoluwak/realtime-api-types" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;With this library, as you get responses from an api, it generates the type for you and saves it to your project, in real time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It also imports the new type and sets it as the return type of your api call. How awesome is that!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just import the helper function and start the server. Thats all. You can then go on with your normal development flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This setup is meant only for development and not for production! You should not deploy this into your production pipeline.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This library was inspired by an old project I stumbled upon, called &lt;a href="https://github.com/jvilk/MakeTypes" rel="noopener noreferrer"&gt;MakeTypes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To get started, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;realtime-api-types &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;There are some configs you need to set.  Go to your &lt;code&gt;package.json&lt;/code&gt; and add the following:&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="nl"&gt;"realtime-api-types"&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;"objectType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/types"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apiPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/apis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fetchType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"axios"&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 shape of the config is:&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;type&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;objectType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;interface&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="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// whether you want to generate interfaces or types &lt;/span&gt;
  &lt;span class="nl"&gt;fetchType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&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="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// how you fetch data, fetch or axios&lt;/span&gt;
  &lt;span class="nl"&gt;typePath&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="c1"&gt;// the path to where you want to save generated types&lt;/span&gt;
  &lt;span class="nl"&gt;apiPath&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="c1"&gt;// the path to where your api methods exist&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start Service
&lt;/h3&gt;

&lt;p&gt;To start the type generator service, run: &lt;code&gt;npx realtime-api-types --init&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Sample &amp;amp; Usage
&lt;/h2&gt;

&lt;p&gt;Wrap your apis in an object and wrap the object with &lt;code&gt;typedApiWrapper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should make your api methods pure, simply return the api call.&lt;/p&gt;

&lt;p&gt;You can use property assignments or methods or both.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that when you're done developing, remove &lt;code&gt;typedApiWrapper&lt;/code&gt; from this file completely.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example &lt;/span&gt;

&lt;span class="c1"&gt;// src/apis/exercise.ts api file&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;typedApiWrapper&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;realtime-api-types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ExerciseApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;typedApiWrapper&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// with fetch, property assignment style&lt;/span&gt;
  &lt;span class="na"&gt;getExercises&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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://example-api.com&lt;/span&gt;&lt;span class="dl"&gt;"&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;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="nx"&gt;res&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="c1"&gt;// with axios, method style&lt;/span&gt;
   &lt;span class="nf"&gt;getExerciseById&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="nx"&gt;string&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;axios&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="s2"&gt;`https://example-api.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// api post method&lt;/span&gt;
  &lt;span class="nf"&gt;postExercise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://example-api.com`&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="c1"&gt;// src/App.tsx file&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;ExerciseApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getExercises&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;With this setup, whenever an api is called at any point in time, the service will intercept and try to generate type from the response.&lt;/p&gt;

&lt;p&gt;When type generation is successful, the example file above would be automatically updated to something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// updated exercise.ts api file&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;typedApiWrapper&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;realtime-api-types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&lt;/span&gt;&lt;span class="dl"&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;GetExercises&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;../types/getExercises&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;GetExerciseById&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;../types/getExerciseById&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;PostExercise&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;../types/postExercise&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ExerciseApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;typedApiWrapper&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// with fetch, property assignment style&lt;/span&gt;
  &lt;span class="na"&gt;getExercises&lt;/span&gt;&lt;span class="p"&gt;:&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;GetExercises&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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://example-api.com&lt;/span&gt;&lt;span class="dl"&gt;"&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;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="nx"&gt;res&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="c1"&gt;// with axios, method style&lt;/span&gt;
   &lt;span class="nf"&gt;getExerciseById&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="nx"&gt;string&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetExerciseById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;axios&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="s2"&gt;`https://example-api.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// api post method&lt;/span&gt;
  &lt;span class="nf"&gt;postExercise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostExercise&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://example-api.com`&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note the difference in structure of return type from fetch and axios.&lt;br&gt;
&lt;code&gt;axios&lt;/code&gt; returns a &lt;code&gt;data: Type&lt;/code&gt;. Do not mix axios and fetch in your project, else you'll get wrong types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Naming Convention
&lt;/h2&gt;

&lt;p&gt;Note the naming convention in the example above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The name of the type file is the same as the name of the &lt;strong&gt;api method called&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The name of the type itself is the same as the name of the api method but in &lt;strong&gt;pascal case&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  React Native or Expo
&lt;/h2&gt;

&lt;p&gt;For this to work with React native or Expo, make sure you follow their guide on how to enable api calls to localhost&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cannot generate enums from response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cannot extend type from different type files. If the response from a call contains object that is similar to another type in another file, it cannot extend it. A new type will be generated in the new file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cannot give custom file names or type names. File name and type name is solely based on the name of the api method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once a type has been generated for an api call, the type will not update with new api calls. You need to delete the previous generated type file to generate a new one.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This library only serves to help you get started quickly and reduce time spent adding types to api calls. You might need to make some updates to the generated types sometimes. It does not solve all your type problems.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>api</category>
      <category>automation</category>
      <category>node</category>
    </item>
  </channel>
</rss>
