The Mini Guide to React Native Optimization for Web3

In this article, we will dive deeper into a few of the chapters of The Ultimate Guide and put it in the context of developing Web3 applications.

While you don't necessarily need to read The Ultimate Guide to understand what will be discussed here, I highly encourage you to do it. It aggregates years of React Native expertise in a single digestible ebook with contributions from the whole React Native community, and it's free!

Pick external libraries carefully

Web3 moves fast - and so do our apps. Shipping fast has a price, and that means you may end up with a huge number of dependencies.

It's up to you to decide which ones are necessary or not, but remember: usually, the more code you have, the slower your TTI (Time To Interactive). In a very simplistic view, your native dependencies will dictate your app's boot time (while in splash screen) and your JavaScript dependencies will dictate the slowness to interact right after booting.

Take care of your polyfills

If you're building for Web3 - either a Dapp or Wallet - you most probably already applied one or more polyfills. It's natural since the web environment matured first and the majority of tools depend on web-specific APIs, starting from browser extension wallets.

But that doesn't mean you should not take good care of your polyfills and other dependencies.

For example, we usually need polyfilling atob() and btoa(), two utilities for encoding and decoding strings to base64. One option would be to install react-native-quick-base64, or other libraries that polyfill all the base64 operations.

If you do not need all those functions, you can manually polyfill only the ones you need in a couple of lines, saving yourself a few kilobytes.

if (typeof btoa === 'undefined') {
global.btoa = function (str) {
return new Buffer(str, 'binary').toString('base64');
};
}
if (typeof atob === 'undefined') {
global.atob = function (b64Encoded) {
return new Buffer(b64Encoded, 'base64').toString('binary');
};
}
view raw polyfills.ts hosted with ❤ by GitHub

Luckily for us though, atob and btoa support was introduced in Hermes, and this specific polyfill might not be needed anymore as soon as React Native 0.74 is released.

Manage dependencies securely

Malicious actors are always trying to find ways to exploit our applications, especially if it involves valuable assets. It is not exclusive to web3, but it is usually more compelling for the attacker.

As best practice for any application, it's important to follow these steps to manage your project dependencies securely.

Step 1: Pin dependencies

By default, package managers install the dependencies following the SemVer ranges. That is, the dependency will be listed similarly to "my-dependency": "^1.0.0", which means that it will accept any updates to the package as long as the new version is >= 1.0.0 and < 2.0.0. More simply, the default accepts any MINOR or PATCH updates.

By removing the ^ indicator, you are effectively pinning the dependency to install that specific version and nothing else. This is a good first step as it prevents malicious code published in future versions from infiltrating your codebase silently.

It's important to note though, that this approach will NOT prevent malicious published versions from the sub-dependencies (dependencies of your dependencies), which are most of the times even bigger than your direct dependencies. To address that, we also need to correctly use the lockfile.

Step 2: Use the lockfile

The lockfile is the file generated by your package manager that tells exactly what version of every single dependency and sub-dependency was installed, as well as checksums to make sure the code is identical.

That is, package-lock.json, yarn.lock, pnpm-lock.yaml or bun.lockb, depending on the package manager you're using.

It should always be committed to your repository, to make sure that every developer in the team gets reproducible builds and extra security by not installing newer versions of dependencies and sub-dependencies.

During development, the regular install command from the package manager will follow exactly the dependency and sub-dependency versions specified in the lockfile, but will also analyze if there are inconsistencies between package.json and the lockfile, trying to fix it.

On CI, use the install commands that keep the lockfile frozen, for a more performant installation that skips the dependency resolution. On npm, this is a different command called npm ci, and on the other package managers, it's just a matter of passing the --frozen-lockfile parameter.

If there are inconsistencies when installing with a frozen lockfile, the installation will fail.

Step 3: Install dependencies from maintainers you trust

The above methods are good measures, but not a silver bullet. Unfortunately, there are still plenty of ways for malicious code to penetrate your codebase. As an example, the latest big exploit happened in December 2023 when an attacker got NPM credentials from a former employee at Ledger.

The attacker was able to publish malicious builds and several dapps were affected because the Ledger library was loading a sub-dependency manually via a script tag loading from a CDN, and without a pinned version. Needless to say, trusting the maintainers of your dependencies, and practicing good security measures are essential.

Always use libraries dedicated to the mobile platform

The JavaScript and React communities are gigantic. There are thousands of packages for the ecosystem, and some of them might work on React Native even if not being built specifically for it.

While that's great for compatibility across platforms, we should prefer libraries that were made for the mobile platform, when available. This is because libraries developed within the web environment in mind assume the web constraints - powerful CPU, unlimited background execution, more stable connection - that are not always true in the mobile environment.

For example, as stated in The Ultimate Guide, iOS is known to be constantly analyzing the resources consumed by the applications and can schedule your app to run in the background more frequently or not depending on how fair you have been using the device's resources.

Crypto libraries

Another example is when choosing libraries to polyfill the crypto API. This one is so important that deserves an article on its own - you can read how to increase speed and security with native crypto libraries on our blog.

But in short, our web3 apps have been using a browser and Node.js polyfills of crypto libraries for too long, while there are already good native alternatives that are way more secure and performant.

Blockchain interface libraries

To send your JSON-RPC calls to your RPC server to interact with the blockchain, you are probably already using a lower-level library to help you abstract some parts of it.

Historically, the go-to solution for developing on the Ethereum network was ethers.js, but it had issues with stability, bundle size, performance, and developer experience that kept bothering users.

Viem, a newer alternative, was born to address those issues. And it has been quickly gaining traction, with over 420k downloads per week at the time of writing this article, and sized about as half as ethers.js. It is mostly platform-agnostic and only needs a TextEncoder polyfill to work with React Native, which the environment lacks until v0.73.

Fortunately, the Hermes team came to the rescue again and recently announced TextEncoder support, which might be coming as soon as v0.74. Read my other article to understand more about how to build web3 apps with React Native and Viem.

size comparison of Viem with competitors

Connect wallet libraries

At some point, you will probably find the need to use a library to help manage the wallet connection. It's needed by every app and usually, there is no reason to reinvent the wheel.

A few of the most popular ones today are RainbowKit, ConnectKit, and Web3Modal. All of them provide great UI and UX and the ability to switch networks, see recent transactions, or use a custom theme. But only Web3Modal currently has a dedicated React Native SDK, which makes it an easy choice for builders today.

By using a native SDK you enable your users with a more performant and seamless experience, deep-linking directly from your app to the wallets and back, giving more confidence to the user and bumping your conversion rates.

Also, the installation process becomes much easier, without having to reach for workarounds such as rendering a web SDK in a WebView. Another benefit is that Web3Modal also provides a quick setup for Wagmi, the hooks library to interact with Ethereum by the same team that built Viem.

Web3Modal in use

Summary

We have only scratched the surface of possible points of optimization for Web3 apps.

Remember, building for web3 is mostly no different from the apps we've been building since the last decade. In The Ultimate Guide for React Native Optimization 2024, our team has covered over twenty topics like these to help you and your company ship faster, smaller, more stable, performant, and beautiful apps.

Insights

Learn more about Web3

Event Cover

Apr 5Talk

Build Universal Web3 Apps With React Native

Learn how to use React Native to build true cross-platform experiences (iOS, Android and Web) for your decentralized apps, from a single codebase.

cover

Mar 6Article

Increase Speed and Security With Native Crypto Libraries

Boost speed and security in React Native with native crypto libraries. Uncover browser or Node.js API polyfill drawbacks, and find efficient solutions.

cover

Jan 12Article

How to Build Universal Lens Protocol Social Apps With React Native

Unlock the potential of web3 social apps with Lens Protocol on the Polygon blockchain. Learn how to build a universal social network app using React Native.

cover

Dec 28Article

Cross-Platform Web3 dApps With React Native

Discover the power of cross-platform development with React Native and Expo in this guide. Learn to build Web3 dApps for web, iOS, and Android.

cover

Nov 14Podcast

Building the Future of Mobile Web3

Do Web3 and React Native go together? Tune in to our discussion about the possibilities & challenges of building cross-platform mobile apps with blockchain.

cover

Nov 13Article

Best DX for React Native Web3 dApps With Web3Modal and Wagmi

Unsatisfied with developer experience of developing for Ethereum? Learn how to build a React Native dApp using Wagmi and Web3Modal.

cover

Oct 25Article

Build Modern Web3 dApps on Ethereum With React Native and Viem

Learn to build modern web3 dApps on Ethereum using React Native and viem. Discover how viem outperforms traditional libraries.

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.