{"id":4899,"date":"2026-10-06T03:27:57","date_gmt":"2026-10-05T21:57:57","guid":{"rendered":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/"},"modified":"2026-10-06T03:27:57","modified_gmt":"2026-10-05T21:57:57","slug":"react-native-guide","status":"publish","type":"post","link":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/","title":{"rendered":"react native &#8211; Guide"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_80 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6ac4526a3f799\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6ac4526a3f799\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#React_Native_The_Bridge_is_a_Bottleneck_and_Your_Build_Pipeline_is_a_Lie\" >React Native: The Bridge is a Bottleneck and Your Build Pipeline is a Lie<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Documentation_is_Lying_to_You\" >The Documentation is Lying to You<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Threading_Model_Where_Performance_Goes_to_Die\" >The Threading Model: Where Performance Goes to Die<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_%E2%80%9CNew_Architecture%E2%80%9D_and_the_JSI\" >The &#8220;New Architecture&#8221; and the JSI<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Build_Pipeline_A_Comedy_of_Errors\" >The Build Pipeline: A Comedy of Errors<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#Memory_Leaks_The_Silent_Killer\" >Memory Leaks: The Silent Killer<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_%E2%80%9CGotcha%E2%80%9D_with_FlatLists_and_Images\" >The &#8220;Gotcha&#8221; with FlatLists and Images<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#CodePush_The_SREs_Best_Friend_and_Worst_Enemy\" >CodePush: The SRE&#8217;s Best Friend and Worst Enemy<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Dependency_Hell_of_React_Native\" >The Dependency Hell of React Native<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Performance_Profiling_Workflow\" >The Performance Profiling Workflow<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Monorepo_Nightmare\" >The Monorepo Nightmare<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Reality_of_%E2%80%9CCross-Platform%E2%80%9D\" >The Reality of &#8220;Cross-Platform&#8221;<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#Security_Its_Not_a_Web_Browser\" >Security: It&#8217;s Not a Web Browser<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#The_Future_Is_it_still_worth_it\" >The Future: Is it still worth it?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#Final_Advice\" >Final Advice<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#Related_Articles\" >Related Articles<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"React_Native_The_Bridge_is_a_Bottleneck_and_Your_Build_Pipeline_is_a_Lie\"><\/span>React Native: The Bridge is a Bottleneck and Your Build Pipeline is a Lie<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>It was 3:14 AM on a Tuesday in 2021. I was staring at a Grafana dashboard that looked like a heart attack. Our flagship app, built on <strong>react native<\/strong> 0.63 at the time, was crashing for 40% of users on Android. The error? <code>java.lang.RuntimeException: ReadableNativeMap.java:115<\/code>. No stack trace. No context. Just a cryptic OOM (Out of Memory) error that only triggered when users tried to checkout using our Stripe integration. We had pushed a &#8220;minor&#8221; UI update that inadvertently triggered a re-render loop in a <code>FlatList<\/code>, which in turn flooded the Bridge with 50MB of JSON data every second. The Bridge didn&#8217;t just slow down; it choked, backed up the message queue, and the Android OS OOM-killed the process to save the kernel.<\/p>\n<p>I spent eighteen hours bisecting commits and digging through <code>node_modules<\/code> to find a single <code>useEffect<\/code> hook that lacked a dependency array. That\u2019s the reality of React Native. It\u2019s not &#8220;Write Once, Run Anywhere.&#8221; It\u2019s &#8220;Write Once, Debug Everywhere until you want to throw your MacBook Pro into a woodchipper.&#8221; If you\u2019re here for a tutorial on how to make a Todo list, go to the official docs. If you want to know why your production app is dropping frames and why your CI\/CD pipeline takes 45 minutes to fail, keep reading.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Documentation_is_Lying_to_You\"><\/span>The Documentation is Lying to You<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The official React Native documentation is written for people living in a vacuum. It assumes you have a clean environment, a single version of Ruby, and that <code>npx react-native init<\/code> works on the first try. It doesn&#8217;t. In the real world, you\u2019re dealing with <code>rbenv<\/code>, <code>nvm<\/code>, <code>cocoapods<\/code> version mismatches, and the specific brand of YAML-hell that comes with <code>bitrise.yml<\/code> or GitHub Actions.<\/p>\n<p>The biggest lie is that you don&#8217;t need to know native code. To run a serious React Native app, you need to be a Senior Android Engineer, a Senior iOS Engineer, and a Senior Web Engineer simultaneously. When the build fails with <code>Duplicate class com.google.common.util.concurrent.ListenableFuture<\/code>, your knowledge of React hooks is worthless. You need to know how to navigate <code>build.gradle<\/code> and exclude transitive dependencies. React Native is an abstraction layer, and all abstractions are leaky. This one leaks like a sieve.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Threading_Model_Where_Performance_Goes_to_Die\"><\/span>The Threading Model: Where Performance Goes to Die<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>To understand why your app stutters, you have to understand the three main threads in React Native (pre-New Architecture):<\/p>\n<ul>\n<li><strong>The JS Thread:<\/strong> Where your business logic lives. If you do a heavy <code>Array.map()<\/code> here, your UI freezes.<\/li>\n<li><strong>The UI Thread (Main Thread):<\/strong> Where the actual native views (UIView, Android.View) are manipulated.<\/li>\n<li><strong>The Shadow Thread:<\/strong> Where Yoga (the layout engine) calculates positions before sending them to the UI thread.<\/li>\n<\/ul>\n<p>The problem is the Bridge. Every time you want to update a view, the JS thread serializes a JSON message, sends it over the Bridge, the Shadow thread calculates the layout, and the UI thread renders it. This is asynchronous. If you\u2019re trying to sync a gesture (like a swipe) with an animation, the round-trip latency across the Bridge creates that &#8220;uncanny valley&#8221; feeling where the UI feels sluggish.<\/p>\n<blockquote><p>\n    <strong>Pro-tip:<\/strong> If you are still using the &#8220;Old Architecture,&#8221; stop doing heavy calculations in <code>render()<\/code>. Use <code>useMemo<\/code> religiously, but more importantly, offload animations to the native thread using <code>useNativeDriver: true<\/code>. If you don&#8217;t, you&#8217;re just burning battery for fun.\n<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"The_%E2%80%9CNew_Architecture%E2%80%9D_and_the_JSI\"><\/span>The &#8220;New Architecture&#8221; and the JSI<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>React Native is currently in a transition period. Version 0.74+ is pushing the &#8220;New Architecture&#8221; hard. They\u2019ve replaced the Bridge with the <strong>JSI (JavaScript Interface)<\/strong>. Instead of serializing JSON, the JS engine (Hermes) now has a direct reference to C++ host objects. This is supposed to be the &#8220;savior&#8221; of the framework.<\/p>\n<p>Is it better? Yes. Is it a headache? Absolutely. Enabling the New Architecture (Fabric for UI, TurboModules for native logic) requires you to rewrite your native modules in C++. If you thought finding a good Swift developer was hard, try finding a React Native developer who is comfortable with C++ memory management.<\/p>\n<pre><code>\n\/\/ Example of a TurboModule spec in TypeScript\n\/\/ This is what the New Architecture expects. No more 'NativeModules.MyModule'\nimport { TurboModule, TurboModuleRegistry } from 'react-native';\n\nexport interface Spec extends TurboModule {\n  readonly getDeviceName: () => string;\n  readonly triggerHeavyCalculation: (input: number) => Promise&lt;string&gt;;\n}\n\nexport default TurboModuleRegistry.getEnforced&lt;Spec&gt;('MyCustomModule');\n<\/code><\/pre>\n<p>The JSI allows for synchronous execution. This means you can finally have a synchronous call to a native database (like Realm or SQLite) without the 100ms Bridge overhead. But it also means if your native code blocks, your JS thread dies. We\u2019ve traded one bottleneck for a different kind of responsibility.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Build_Pipeline_A_Comedy_of_Errors\"><\/span>The Build Pipeline: A Comedy of Errors<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s talk about <code>pod install<\/code>. In a 10-person team, someone will eventually update their macOS, which updates Ruby, which breaks <code>ffi<\/code>, which breaks CocoaPods. Suddenly, the entire team is blocked because <code>Hermes-engine<\/code> won&#8217;t compile for <code>arm64<\/code> simulators.<\/p>\n<p>In my experience, 40% of an SRE&#8217;s time on a React Native project is spent fixing the CI. Here is a typical failure pattern in a <code>config.yml<\/code> for CircleCI:<\/p>\n<ol>\n<li>Node version mismatch between local and CI (Use <code>.nvmrc<\/code>, people!).<\/li>\n<li>Android SDK licenses not accepted on the runner.<\/li>\n<li>The <code>node_modules<\/code> cache is poisoned because someone added a dependency via <code>npm<\/code> instead of <code>yarn<\/code> (or vice versa).<\/li>\n<li>iOS code signing certificates expired (Fastlane <code>match<\/code> is the only sane way to handle this).<\/li>\n<li>The runner runs out of disk space because the <code>ios\/build<\/code> folder is 12GB.<\/li>\n<li>Metro bundler hangs because it found a duplicate Haste module map.<\/li>\n<\/ol>\n<p>To survive this, you need a strict <code>lockfile<\/code> policy. If a PR changes <code>yarn.lock<\/code> and <code>package-lock.json<\/code> simultaneously, reject it. If a PR adds a native dependency without a corresponding <code>podfile.lock<\/code> update, reject it. The build must be deterministic, or you will spend your Fridays debugging <code>ld: library not found for -lDoubleConversion<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Memory_Leaks_The_Silent_Killer\"><\/span>Memory Leaks: The Silent Killer<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Web developers think that because JS has a garbage collector, they don&#8217;t need to worry about memory. In React Native, this is a dangerous assumption. When you create a native view (like a <code>MapView<\/code> or a <code>Video<\/code> component), the JS object is just a handle. If you unmount the component but the native side doesn&#8217;t release the resource, you have a leak.<\/p>\n<p>I once saw an app&#8217;s memory usage climb from 200MB to 1.5GB in ten minutes. The culprit? An event listener on the <code>DeviceEventEmitter<\/code> that wasn&#8217;t removed in <code>componentWillUnmount<\/code>. Every time the user navigated to the &#8220;Settings&#8221; screen, a new listener was created. The JS objects were small, but they were holding onto large native context objects.<\/p>\n<pre><code>\n\/\/ The \"I'm going to crash your app\" pattern\nuseEffect(() => {\n  const subscription = DeviceEventEmitter.addListener('onDataReceived', (data) => {\n    setGlobalState(data);\n  });\n  \/\/ Missing: return () => subscription.remove();\n}, []);\n<\/code><\/pre>\n<p>To debug this, you can&#8217;t just use the Chrome DevTools. You need <strong>Xcode Instruments<\/strong> (specifically the &#8220;Allocations&#8221; and &#8220;Leaks&#8221; templates) and <strong>Android Studio Profiler<\/strong>. You have to look at the &#8220;Native Heap&#8221; vs. the &#8220;JS Heap.&#8221; If the Native Heap is growing while the JS Heap is flat, your problem is in the Bridge or a Native Module.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_%E2%80%9CGotcha%E2%80%9D_with_FlatLists_and_Images\"><\/span>The &#8220;Gotcha&#8221; with FlatLists and Images<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If you have a list of 500 items and each item has a 2MB image, React Native will try to render them all if you aren&#8217;t careful. Unlike a web browser, which is quite good at handling large DOMs, React Native&#8217;s <code>FlatList<\/code> is a complex beast that tries to virtualize rendering.<\/p>\n<p>The problem: <code>windowSize<\/code>. The default <code>windowSize<\/code> is 21 (10 screens up, 10 screens down). If your list items are complex, React Native is keeping 21 screens worth of native views in memory. On a low-end Android device with 2GB of RAM, this is a death sentence.<\/p>\n<blockquote><p>\n    <strong>Note to self:<\/strong> Always set <code>removeClippedSubviews={true}<\/code> on Android. It\u2019s buggy on iOS sometimes, but on Android, it\u2019s the only thing keeping your <code>FlatList<\/code> from eating the entire heap. Also, use <code>initialNumToRender<\/code> and <code>maxToRenderPerBatch<\/code> to throttle the Bridge.\n<\/p><\/blockquote>\n<p>And for the love of all that is holy, use a library like <code>react-native-fast-image<\/code>. The default <code>Image<\/code> component in React Native is trash. It doesn&#8217;t handle caching well, and it doesn&#8217;t prioritize downloads. <code>FastImage<\/code> wraps <code>SDWebImage<\/code> (iOS) and <code>Glide<\/code> (Android), which are the industry standards for a reason.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"CodePush_The_SREs_Best_Friend_and_Worst_Enemy\"><\/span>CodePush: The SRE&#8217;s Best Friend and Worst Enemy<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Microsoft&#8217;s CodePush allows you to push JS updates directly to users, bypassing the App Store and Play Store review process. This is incredible for fixing a critical bug in 10 minutes. It\u2019s also a great way to bypass QA and break your app for everyone.<\/p>\n<p>The danger with CodePush is <strong>Native Dependency Mismatch<\/strong>. If your JS code expects a new version of a native module (e.g., you added <code>react-native-reanimated<\/code>), but the user is running an old binary that doesn&#8217;t have that native code, the app will crash on launch. CodePush does not update the native binary. It only updates the <code>index.bundle<\/code>.<\/p>\n<p>We solved this by implementing a strict versioning contract. Every CodePush release is tied to a specific <code>nativeBuildNumber<\/code>. If the binary version doesn&#8217;t match the bundle&#8217;s target version, the update is ignored. It sounds simple, but I&#8217;ve seen teams lose weeks of work because they &#8220;CodePushed&#8221; a change that required a <code>pod install<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Dependency_Hell_of_React_Native\"><\/span>The Dependency Hell of React Native<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In a standard Node.js project, a dependency is just some JS code. In React Native, a dependency is often a wrapper around a CocoaPod and a Gradle module. This means you are at the mercy of the maintainer&#8217;s knowledge of three different ecosystems.<\/p>\n<p>Take <code>react-native-firebase<\/code>. It\u2019s a fantastic library, but it\u2019s also a massive dependency. When Google updates the Firebase Android SDK, <code>react-native-firebase<\/code> has to update. If they don&#8217;t, you might find yourself unable to build for Android because of a <code>minSdkVersion<\/code> conflict. You end up in a situation where you can&#8217;t update Library A because it depends on an old version of Library B, but Library C requires a new version of Library B.<\/p>\n<p>The solution? <strong>Patch-package<\/strong>. If you aren&#8217;t using <code>patch-package<\/code>, you aren&#8217;t doing React Native in production. You will inevitably find a bug in a library&#8217;s <code>.podspec<\/code> file or a <code>.java<\/code> file that the maintainer hasn&#8217;t fixed yet. Instead of forking the repo and dealing with the overhead of maintaining a fork, you patch it locally and commit the patch.<\/p>\n<pre><code>\n\/\/ Example: patching a broken build.gradle in a third-party library\n\/\/ patches\/react-native-some-library+1.2.3.patch\n--- a\/node_modules\/react-native-some-library\/android\/build.gradle\n+++ b\/node_modules\/react-native-some-library\/android\/build.gradle\n@@ -10,7 +10,7 @@\n     compileSdkVersion 34 \/\/ Manually bumped because the maintainer is MIA\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"The_Performance_Profiling_Workflow\"><\/span>The Performance Profiling Workflow<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>When someone says &#8220;the app is slow,&#8221; you need data. Don&#8217;t guess. Use the following workflow:<\/p>\n<ol>\n<li><strong>Enable the Perf Monitor:<\/strong> Look at the JS and UI frame rates. If UI is 60fps but JS is 10fps, you have a heavy JS calculation. If JS is 60fps but UI is 10fps, you have too many native views or off-screen rendering issues.<\/li>\n<li><strong>Flipper (Legacy but useful):<\/strong> Use the &#8220;React DevTools&#8221; to find unnecessary re-renders. Use the &#8220;Network&#8221; tab to see if you&#8217;re fetching 10MB of data when you only need 10KB.<\/li>\n<li><strong>Hermes Debugger:<\/strong> Since RN 0.70, Hermes is the default. Use the <code>chrome:\/\/inspect<\/code> tool to profile the JS heap specifically for Hermes.<\/li>\n<li><strong>Systrace:<\/strong> This is the nuclear option. It gives you a breakdown of exactly what the CPU is doing across all threads. It will show you if the &#8220;Ganesh&#8221; (Android&#8217;s rendering engine) is struggling with a specific layer.<\/li>\n<\/ol>\n<p>One specific issue we found was &#8220;Overdraw.&#8221; On Android, if you have a background color on your <code>View<\/code>, and that <code>View<\/code> is inside another <code>View<\/code> with a background color, the GPU has to paint those pixels twice. In a complex screen, you might be painting the same pixel 5 or 6 times. This kills performance on mid-range devices. The fix? Remove unnecessary backgrounds and use <code>collapsable={true}<\/code> on Android views.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Monorepo_Nightmare\"><\/span>The Monorepo Nightmare<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If you&#8217;re running React Native in a monorepo (using Nx or Turborepo), God help you. Metro, the React Native bundler, does not like symbolic links. It has improved recently, but for years, you had to use a custom <code>metro.config.js<\/code> just to make it see code in <code>packages\/common<\/code>.<\/p>\n<pre><code>\nconst path = require('path');\nconst { getDefaultConfig, mergeConfig } = require('@react-native\/metro-config');\n\nconst workspaceRoot = path.resolve(__dirname, '..\/..');\nconst projectRoot = __dirname;\n\nconst config = {\n  watchFolders: [workspaceRoot],\n  resolver: {\n    nodeModulesPaths: [\n      path.resolve(projectRoot, 'node_modules'),\n      path.resolve(workspaceRoot, 'node_modules'),\n    ],\n    disableHierarchicalLookup: true,\n  },\n};\n\nmodule.exports = mergeConfig(getDefaultConfig(__dirname), config);\n<\/code><\/pre>\n<p>Even with this, you&#8217;ll run into issues where <code>react-native<\/code> is hoisted to the root <code>node_modules<\/code>, but the native build scripts expect it to be in the local <code>node_modules<\/code>. You&#8217;ll end up writing &#8220;nohoist&#8221; rules in your <code>package.json<\/code> and praying to the NPM gods.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Reality_of_%E2%80%9CCross-Platform%E2%80%9D\"><\/span>The Reality of &#8220;Cross-Platform&#8221;<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>You will eventually write native code. Whether it&#8217;s a custom <code>IntentFilter<\/code> on Android to handle deep linking or a <code>UNUserNotificationCenterDelegate<\/code> on iOS for push notifications, you cannot escape the native platforms. The dream of a pure-JS mobile app is only possible for the simplest of CRUD apps.<\/p>\n<p>The real value of React Native isn&#8217;t that you only write JS. It&#8217;s that you can share the <strong>business logic<\/strong>. Your API client, your state management (Redux, Zustand, whatever), and your validation logic can be shared. But your UI layer will always have platform-specific tweaks. If you try to make the Android app look exactly like the iOS app, you will frustrate your users. Android users want a back button; iOS users want a swipe-back gesture. React Native makes it easy to handle both, but you have to actually do the work.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Security_Its_Not_a_Web_Browser\"><\/span>Security: It&#8217;s Not a Web Browser<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I&#8217;ve seen too many developers store API keys in their <code>app.json<\/code> or <code>.env<\/code> files. In a web app, you can hide secrets behind a backend. In a mobile app, anything in your JS bundle is public. If I download your APK, I can run <code>strings index.android.bundle | grep \"sk_live_\"<\/code> and find your Stripe secret key in five seconds.<\/p>\n<p>Use <strong>Keychain<\/strong> on iOS and <strong>Keystore<\/strong> on Android. Use libraries like <code>react-native-keychain<\/code> to store sensitive data. Never, ever store a JWT or a private key in <code>AsyncStorage<\/code>. <code>AsyncStorage<\/code> is just a plain-text file on the disk. On a rooted Android device, it\u2019s trivial to read.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Future_Is_it_still_worth_it\"><\/span>The Future: Is it still worth it?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>With the rise of Flutter and the improvements in Native (SwiftUI and Jetpack Compose), people keep asking if React Native is dead. It\u2019s not. The ecosystem is too big. The ability to &#8220;Over-the-Air&#8221; update your app is too powerful for businesses to ignore. But the &#8220;hype&#8221; phase is over. We are now in the &#8220;maintenance and maturity&#8221; phase.<\/p>\n<p>React Native is a tool for managing complexity. It allows a smaller team to ship to two platforms, but it requires that team to be more technically diverse. If you treat it like a web framework, it will punish you. If you treat it like a sophisticated C++\/Native\/JS hybrid, you can build world-class apps.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Final_Advice\"><\/span>Final Advice<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Stop looking for the &#8220;best&#8221; navigation library; just use <code>react-navigation<\/code>. Stop trying to optimize your JS code until you&#8217;ve checked your image sizes and Bridge traffic. And for the love of your sanity, keep your native dependencies to a minimum. Every library you add is a potential build failure waiting to happen during your next release cycle. If you can write it yourself in 50 lines of Swift or Kotlin, do it. You\u2019ll thank yourself when the next version of React Native drops and your app actually compiles.<\/p>\n<p>React Native is a powerful, frustrating, brilliant, and broken mess. It&#8217;s the best tool we have for cross-platform development, but only if you respect the platforms it&#8217;s running on. Now go delete your <code>node_modules<\/code> and try building again. You know you have to.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Related_Articles\"><\/span>Related Articles<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Explore more insights and best practices:<\/p>\n<ul>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/docker-tutorial-build-ship-and-run-apps-anywhere\/\">Docker Tutorial Build Ship And Run Apps Anywhere<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/10-devops-best-practices-for-faster-software-delivery-5\/\">10 Devops Best Practices For Faster Software Delivery 5<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/install-php-in-ubuntu-18-04\/\">Install Php In Ubuntu 18 04<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>React Native: The Bridge is a Bottleneck and Your Build Pipeline is a Lie It was 3:14 AM on a Tuesday in 2021. I was staring at a Grafana dashboard that looked like a heart attack. Our flagship app, built on react native 0.63 at the time, was crashing for 40% of users on Android. &#8230; <a title=\"react native &#8211; Guide\" class=\"read-more\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\" aria-label=\"Read more  on react native &#8211; Guide\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4899","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>react native - Guide - ITSupportWale<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"react native - Guide - ITSupportWale\" \/>\n<meta property=\"og:description\" content=\"React Native: The Bridge is a Bottleneck and Your Build Pipeline is a Lie It was 3:14 AM on a Tuesday in 2021. I was staring at a Grafana dashboard that looked like a heart attack. Our flagship app, built on react native 0.63 at the time, was crashing for 40% of users on Android. ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\" \/>\n<meta property=\"og:site_name\" content=\"ITSupportWale\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-05T21:57:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Techie\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Techie\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\"},\"author\":{\"name\":\"Techie\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\"},\"headline\":\"react native &#8211; Guide\",\"datePublished\":\"2026-10-05T21:57:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\"},\"wordCount\":2433,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\",\"name\":\"react native - Guide - ITSupportWale\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\"},\"datePublished\":\"2026-10-05T21:57:57+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/itsupportwale.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"react native &#8211; Guide\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"name\":\"ITSupportWale\",\"description\":\"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\",\"name\":\"itsupportwale\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"contentUrl\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"width\":1119,\"height\":144,\"caption\":\"itsupportwale\"},\"image\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\",\"name\":\"Techie\",\"sameAs\":[\"https:\/\/itsupportwale.com\",\"iswblogadmin\"],\"url\":\"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"react native - Guide - ITSupportWale","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/","og_locale":"en_US","og_type":"article","og_title":"react native - Guide - ITSupportWale","og_description":"React Native: The Bridge is a Bottleneck and Your Build Pipeline is a Lie It was 3:14 AM on a Tuesday in 2021. I was staring at a Grafana dashboard that looked like a heart attack. Our flagship app, built on react native 0.63 at the time, was crashing for 40% of users on Android. ... Read more","og_url":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/","og_site_name":"ITSupportWale","article_publisher":"https:\/\/www.facebook.com\/Itsupportwale-298547177495978","article_published_time":"2026-10-05T21:57:57+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png","type":"image\/png"}],"author":"Techie","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Techie","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#article","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/"},"author":{"name":"Techie","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d"},"headline":"react native &#8211; Guide","datePublished":"2026-10-05T21:57:57+00:00","mainEntityOfPage":{"@id":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/"},"wordCount":2433,"commentCount":0,"publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/itsupportwale.com\/blog\/react-native-guide\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/","url":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/","name":"react native - Guide - ITSupportWale","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/#website"},"datePublished":"2026-10-05T21:57:57+00:00","breadcrumb":{"@id":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itsupportwale.com\/blog\/react-native-guide\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/itsupportwale.com\/blog\/react-native-guide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/itsupportwale.com\/blog\/"},{"@type":"ListItem","position":2,"name":"react native &#8211; Guide"}]},{"@type":"WebSite","@id":"https:\/\/itsupportwale.com\/blog\/#website","url":"https:\/\/itsupportwale.com\/blog\/","name":"ITSupportWale","description":"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides","publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/itsupportwale.com\/blog\/#organization","name":"itsupportwale","url":"https:\/\/itsupportwale.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","contentUrl":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","width":1119,"height":144,"caption":"itsupportwale"},"image":{"@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Itsupportwale-298547177495978"]},{"@type":"Person","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d","name":"Techie","sameAs":["https:\/\/itsupportwale.com","iswblogadmin"],"url":"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4899","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/comments?post=4899"}],"version-history":[{"count":0,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4899\/revisions"}],"wp:attachment":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/media?parent=4899"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/categories?post=4899"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/tags?post=4899"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}