Sunday, 13 July 2025

Updating React Native (my journey)

Upgrading a React Native Project to a newer version

My Journey, in the hopes it will be useful to others. 

So, it turns out that upgrading a react native project is a major task, not the least of which is there the error reporting is literally all over the place.

I have a project currently running in 0.73 and I need to upgrade it to keep Google Playstore happy.

(Min SDK needs to be 35 now).

(Android, Windows environment)

First off all, the upgrade tools have never worked for me. , not even when moving from one version of RN to the next one up.

Also, I did  not write the original version of the project, and I'm not convinced the original author actually understood RN very well.

Patching the project in place never seems to work, so my approach for upgrades is:

Start a new project with the latest RN version:

https://reactnative.dev/docs/getting-started-without-a-framework

(Note: Not using expo, it does not appear suitable for my requirements)

Copy source code from existing project, including assets, but leave android folder alone for the time being.

npx react-native run-android

I took the opportunity to get all dependant packages to the latest version, by just iterating installing each package as it detected it was missing. Sometime iterating is as simple as hitting reload, sometimes you have to "run-android" again. (And sometimes you need to clear all the caches and restart).

Here are some of the packages that needed special handling:

@nozbe/watermelondb

This is an asynchronous wrapper around a native database, typically sqlite. It seems to work tolerably well once you take the time to properly .read the documentation. You do need to install a particular version of babel as watermelondb make extensive use of decorations.
Getting this to run took a while, and the error in question was an unhelpful "n is not a function" message.
After some trial and error, I found that the  @action  decoration was failing during the babel rendering phase. This is because it appears to be obsolete, and by replacing with @reader or @writer  decorations it will now initialise properly. Remember to update your imports.

@nozbe/withobservables

This has moved. Do not install as a separate package as it is now included in @nozbe/watermelondb. Change your imports to:

import { withObservables } from '@nozbe/watermelondb/react';

recompose

The project made considerable use of recompose which is no longer supported, and will crash on startup. The best fix is to not use it at all, but a quick workaround to stop it falling over is:to patch node_modules/recompose/dist/Recompose.cjs.js and replace all references to React.createFactory with a call to:

export function createFactory(type) {
  return React.createElement.bind(null, type);
}

Clearly it is better to rewrite your code to not use recompose, but that is not always straightforward.

react-native-ui-lib

Does not work with version 0.79, and throws an error like: 
Attempt to invoke virtual method 'void com.facebook.react.uimanager.UlManagerModule.onBatchComplete()' on a null object reference
after the keyboard appears in a text input.
Theoretically it can be patched but I just uninstalled the module and removed all references.

debugging

0.79 has changed the debugger and the console output. Hitting "j" in the metro screen should open it, and as a debugger it seems much better at source code handling than prior versions. However, if your project is crashing the debugger can decide it doesn't want to connect.
The trick I found was to close the app on the device, restart, hit reload, and then hit the reconnect button in the debugger window before it has finished loading. That is usually sufficient to get the source maps loaded and to allow you to start putting in breakpoints

missing imports

RN is aggravatingly poor at letting you know that an import has failed to work. For instance:

import {jwt_decode} from 'jwt-decode';
It turns out in the latest version of jwt-decode, the developer changed the import from jwt_decode to jwtDecode. There were no error messages, I just traced it to the point where I was attempting to call jwt_decode(token) and realised it wasn't proceeding past there. So, double check imports, because RN is not very reliable. Sometimes it will tell you there is an issue, sometimes not.

The many ways of restarting 

RN is, lets face it, a Frankenstienian monstrosity. It has a lot of moving parts and many different places you need to look to work out what is going wrong. During development, you need to frequently rebuild.
Here are some of approaches, from simplest to most thorough:
  1. Change your code and save changes: If your project is basically running, RN will pick up any changes and reapply. 
  2. Hit Reload: Hitting "r" on the metro server screen, or the reload button on the error screen on the device should reload any changes.
  3. npx react-native run-android: should rebuild everything, including the underlying android SDK java components. Generally a good idea if you install or uninstall modules, but you can get away with just a reload IF the module is pure javascript/typescript. It's not always easy to tell.
  4. npx react-native start --reset-cache: Do this after the run-android step if something is not working when you think it should be. 
  5. clear caches and reinstall modules: See cleanall.bat below.

cleanall.bat

@echo off
echo Deleting metro cache
rd %localappdata%\Temp\metro-cache /s /q
del %localappdata%\Temp\haste-map*
echo Cleaning build
cd android
call gradlew clean
cd ..
echo Deleting node_modules
rd node_modules /q /s
echo Cleaning npm cache
call npm cache clean --force
echo Installing modules
call npm install --legacy-peer-deps
echo Done

This will clear all the caches and reinstall the modules. This will sometimes sort out strange behaviours.

Reconnecting

Sometimes the device loses track of where the metro server is, and vice-versa.
adb reverse tcp:8081 tcp:8081

should map the ports appropriately. Look up adb parameters to manage more than one device.

Once this is done, close and restart the app on the device for a clean reconnect.

Patching

npm modules get out of date with the current version of RN and need to be tweaked or modified to get your project to run.
Fortunately, there is a way of tweaking a module in your own project without having to go for a full scale fork in git.
patch-package https://www.npmjs.com/package/patch-package creates a patch file from your changes and reapplies the change when you do a fresh install.
Note: It  does require git to be available from the command line to run properly


 





Updating React Native (my journey)

Upgrading a React Native Project to a newer version My Journey, in the hopes it will be useful to others.  So, it turns out that upgrading a...