The Mini Guide to React Native Optimization for Web3

In short

This article is a miniature companion to the recently released The Ultimate Guide to React Native Optimization 2024, where our experts compiled best practices in the React Native ecosystem regarding stability, performance, resource usage, user experience, maintenance costs, and time-to-market.

Introduction

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 <rte-code>atob()<rte-code> and <rte-code>btoa()<rte-code>, two utilities for encoding and decoding strings to base64. One option would be to install <rte-code>react-native-quick-base64<rte-code>, 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.

Luckily for us though, <rte-code>atob<rte-code> and <rte-code>btoa<rte-code> 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 <rte-code>"my-dependency": "^1.0.0"<rte-code>, which means that it will accept any updates to the package as long as the new version is <rte-code>>= 1.0.0<rte-code> and <rte-code>< 2.0.0<rte-code> . More simply, the default accepts any MINOR or PATCH updates.

By removing the <rte-code>^<rte-code> 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, <rte-code>package-lock.json<rte-code>, <rte-code>yarn.lock<rte-code>, <rte-code>pnpm-lock.yaml<rte-code> or <rte-code>bun.lockb<rte-code>, 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 <rte-code>package.json<rte-code> 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 <rte-code>npm ci<rte-code>, and on the other package managers, it's just a matter of passing the <rte-code>--frozen-lockfile<rte-code> 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 <rte-code>crypto<rte-code> 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 <rte-code>ethers.js<rte-code>, 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 <rte-code>TextEncoder<rte-code> 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.

Latest update:
March 13, 2024

FAQ

No items found.
React Galaxy City
Get our newsletter

By subscribing to the newsletter, you give us consent to use your email address to deliver curated content. We will process your email address until you unsubscribe or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

Callstack astronaut
Download our ebook

I agree to receive electronic communications By checking any of the boxes, you give us consent to use your email address for our direct marketing purposes, including the latest tech & biz updates. We will process your email address and names (if you have entered them into the above form) until you withdraw your consent to the processing of your names, or unsubscribe, or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

By pressing the “Download” button, you give us consent to use your email address to send you a copy of the Ultimate Guide to React Native Optimization.