Upgrading a React Native App
8 min read
I recently had to go through the rather painful process of upgrading a React Native app for the first time. This was an upgrade from version 0.63.3 to 0.65.1. It didn't sound like too big of a jump, but turned out to be rather fiddly, so I've created a guide below, detailing all the steps I had to take in order to get the app working.
Before we jump in...
- For those brand new to all this, to upgrade your packages, what you need to do is open your
package.json
file, amend packages for the version you want, save, then runyarn install
(assuming you're usingyarn
, ornpm install
if usingnpm
). - If you don't use Expo, or have ejected from Expo, you might need to run additional commands to ensure, for instance, that your Podfiles are up to date.
- Get familiar with the list of resources I've listed in the appendix below. I'd really recommend listening to the React Native Radio podcast specifically dedicated to highlighting just how much of a pain upgrading a React Native app is, if only for solidarity. ๐ฌ
React Native apps built on top of Expo
- If your app uses Expo under the hood, figure out if you're using a managed or bare workflow. Expo takes care of the RN upgrade for you if you're on a managed workflow, but this means you'll be limited by what version of React Native you can upgrade to, based on what Expo's latest SDK supports.
- I was on a bare workflow, so I don't exactly know firsthand, what the upgrade process is like for managed workflows. My understanding is that you'd just need to upgrade to the latest Expo SDK version.
How to upgrade a React Native app
- For a bare workflow, use the React Native upgrade helper to understand what the required base changes are. This open source app basically shows what the differences would be if you spun up two new React Native apps today with the versions you specified. You should thus be able to see what new changes you need to introduce to get your old app working with the new React Native API.
- Depending on how much configuration you've done to your own app, you may be able to just copy and paste the new versions of the various files. The app I was working on had introduced numerous custom build steps, so I needed to go line by line to figure out what the new changes were trying to do, before copying across.
- I initially tried to do the upgrade in a single step. When I got to building the app, I ran into all sorts of errors. Though I managed to make good progress with solving most of them, I eventually ended up at a dead-end, when nothing I tried seemed to work. I decided to cut my losses and start the process again, this time taking incremental steps, i.e. upgrading from 0.63.3 to 0.64, then 0.64 to 0.65. There were still lots of errors to fix, but I managed to deduce that the big breaking change was happening in the 0.64 to 0.65 step, allowing me to do more scoped error fixing by reading through a smaller set of changelogs and really understanding what had changed beneath the hood.
- Whilst the list of changes to be done may look small when looking at what the React Native upgrade helper suggests, the problems come from all the various packages and dependencies you'll likely be using in your app. The bulk of the errors came from mismatched and out of date versions of dependencies (another reason why upgrading versions incrementally may be a good idea, since it allows you to make a call on whether you really need to upgrade to the cutting edge versions of the various packages you use).
- This was the step in the entire process that took the longest. What I basically did was to make the changes to the build process for iOS and Android, upgraded the packages I needed, run the build process for iOS and Android, see it fail, google the error, make the fix and repeat. Because the app I'm working on takes a while to build, this can be fairly slow-going and requires a good deal of patience! ๐ฅฑ
- The minimum React Native version we needed was 0.65.0, for the features we needed to implement. At that point, React Native v. 0.66.0 was already out, though only for a couple of weeks. This probably meant that there's still all sorts of kinks and bugs being worked out, which in all likelihood, makes debugging harder. If you're not willing to risk being a bug explorer, perhaps wait for 2-3 months before upgrading to the latest available version. ๐
- Whilst the app I'm working on has ejected from Expo, it still relies on Expo for certain features. The Expo SDK itself goes through quite a lot of changes including moving modules in and out of the core package. I therefore needed to make some changes to the Expo bits of our code base, including installing new packages that have been deprecated by Expo, but which we don't yet have the time to rewrite our code base for. Here again, the changelog is your friend!
- Once you've Googled your way through all the errors and gotten your builds working for iOS and Android, take a breather. When you've caught your breath, consider if there are any packages you currently use that may be worth upgrading (and going through all the build issues hell again). ๐
- For e.g., I decided to take this opportunity to upgrade our
react-navigation
version from 5 to 6. This would introduce some breaking changes to our app, but it was manageable and something I could confidently fix in a couple of hours. Considering we'd be making greater use of otherreact-navigation
features in the coming months, it made sense to do the rewrite now, rather than later. - It might be helpful to run something like
yarn outdated
to identify massively out of date packages you might still be using. - If you use Typescript, remember to upgrade your
@types
packages! - The one tip I'd offer here is just to ensure you do these upgrades one by one. There will likely be dependency issues, so you want to be sure at all times, about what package is causing what problems.
- For e.g., I decided to take this opportunity to upgrade our
- If you've reached the point where you've got your app building for iOS and Android without issues, remember to check that your test runner still works and your test suites are all passing!
- I actually had to spend quite a lot of time getting my Jest test runner working again because of some complications with Expo and version mismatches. ๐
- The fix involved upgrading certain packages as fixes had since been made by the community, but also downgrading others, where there were no fixes. You'll need to make a judgement call to decide what features you actually need, and thus what package version is a must-have vs. a nice-to-have.
Concluding steps
- Whew! Now that you've upgraded all your packages, got your builds working and tests passing, you might want to run through your entire app and so a bit of manual QA on each of the screens, just to check that everything is rendering properly.
- This is perhaps unnecessary if you use snapshot tests. We don't, and I wanted to be extremely certain that the upgrade hadn't inadvertently caused some UI issues.
- When running your app, you might come across a bunch of yellow warnings in your console, shouting at you about deprecations or suggesting certain changes. These don't stop your app from working, but you should make a list of these warnings and decide how important they are to fix before they DO become an issue in the future.
- If you reached this point, WELL DONE! You made it to the end and got your first React Native upgrade working. ๐ It wasn't so bad in the end right, and I'll bet that you now have a better understand of how things like Gradle and Podfiles work. ๐
Appendix: Resources
- React Native Radio podcast episode on "Strategies for upgrading React Native".
- React Native versions
- React Native changelog
- React Native documentation on upgrading