This is not the first time I've upgraded any react-native projects.
I've done it a few times over the years and will be sharing out what I've learnt so far.
To give you some context regarding the topic, the very same project was upgraded to 0.59.10
since the creation with react-native init
,
to comply with the Google Play store regulation for having 64 bit version of the app.
Everything works out fine with 0.59.10
, for the next couple of months.
Especially one that need to deal with linking of native libraries, most of the packages have no issue with the good old react-native link
command.
With that said, I can focus on building features and be very productive with my hours spent working on projects (personal or client projects).
Which makes me fully occupied with work, and thus not having time for writing/bloging.
Now, let's get back to the topic.
Before any major upgrade (i.e: 0.5x.x
to 0.60.0
), you need to know things are going to be broken, libraries will have issues,
deprecated API(s) will affects your app (rather than just deprecation warning), module dependencies and UI look or behaviour will have impacts.
There are a lot of stuffs that can possibly went wrong. So keep in mind that, upgrading is one part, regression test for your upgraded app is another part.
For any version upgrades you are going to perform, it is a good practice to have an overview of your dependencies
, spot for native linked libraries and do a quick check on the potential issues after upgrade.
For non native linked library, there might be issue is there is a major changes in react
version itself, but most of the time this will no less of a issue.
In my case, there are 116 packages(dev packages excluded) installed at the point during my upgrades, and 38 of them are natively linked.
So I am sure it's going to take time for the upgrade to complete. Plus after some searching the internet, I am very sure that the upgrade cannot be completed in just few hours of time (in my case).
So now you are aware that what a major upgrade will be like, and the time that it will take.
If there are no major blocker that are holding you back with the current version, I would suggest delaying the upgrade for a few reasons:
react-native
Do it when you are in better position (let say you are ahead with your timeline), or when you have absolute no better choice than to upgrade (i.e: to upgrade to 64 bit support.)
If you are in the midst of some feature, and that feature requires for a react-native
version upgrade before continuing, I actually suggest going with alternatives if you can. Or do the upgrade separately, and do enough testing after the upgrade, otherwise you will find yourselves in a rabbit hole trying to fix some errors of another issue in order to make some other issues resolved. You don't want that.
For example, App Store stops accepting app with WebView since April. You need to use react-native-webview
(from a specific version onwards), and have your react-native
project to be at minimum xxx version.
You thought upgrading is the only option. Well if you are in good hand, for example your project is new and have less dependencies. Upgrading seems like a good choice if that is the case.
Otherwise you want just settled with the alternative, for example, removing the RCTWebView with a script that run on a postinstall
or after_install
Podfile, and you are good to god.
Chances are if you proceed with the upgrade, your react-navigation
verison will not compatible with the new version, and you need to upgrade react-navigation
as well. Say, from v3
to v4
with some changes in behaviour. (More on this later)
If you are like me, who delaying the upgrade until you have no other choices. Chances are, you have a few major versions to choose from, since the release schedule of React Native now follows a monthly release train. So the question for us is which version to use?
Well, if you have a major upgrade, normally I take the latest version within the major upgrade.
Depending on the major version of your choice, for my case from 0.59.10
, I can upgrade to 0.60.x
, 0.61.x
or 0.62.x
. (0.63.x
release candidate are not into consideration)
To have an overview of the available version, use this command.
npm show react-native versions
My choice of upgrade is to get the latest stable version for this project. Cause if I don't do that, I will need to upgrade again sooner, and I am having huge backlogs in the pipeline after the upgrade. So I want to maximize the window before the next upgrade.
Bear in mind that the latest stable version might not always be the best choice to upgrade to. Sometimes you want to upgrade to a version lower that that.
Reason for that is the latest stable version might have breaking chances that no open source libraries has adapted yet.
How to know which to choose from?
package.json
file and have a look at the dependencies
to get an idea. You are the developer of your project and should know more about which libraries will more likely to break after the upgrade.I used to do it in a separate branch, but for this particular upgrade, I am doing it in a cloned folder.
Note: Not cloning from remote and reinstalling everything, I copy/pasted the entire folder to a different directory and start working on the upgrade.
Reason?
node_modules
and Pods
when I already have it.node_modules
and so on).
Upgrade is going on, same goes for bug fixing and feature development. I am still actively developing on the non-upgraded branch.You want your app to still working if you decided to abort the upgrade half way, or start over again. (Yeah, sometimes, you just have to start over again.)
While juggling betweeen bug fixing, new features development, some optimizations, maintaining the code and version upgrade, I want to avoid the upgrade to potentially stop me from my regular work flow. If the upgrade went wrong, I can still fix bug and ship new features of my app to App/Play stores on the main project.
Check for code changes before applying it in the project.
Optionally, you can upgrade with npx react-native upgrade
.
However, from the memory of the time I last used it, I don't have a good experience using that.
I have to resolved conflicts and the worst part was changes on iOS project.pbxproj
files which is a pain.
Ever since then I use upgrade helper and hand-picked the code and manually apply it to my existing project. I am happy with that and is aware and consious of what I've changes, so I know where to look for if anything went wrong.
If my case, upgrading to 0.62.2
only need to change 15 files, which is faster to do hand-picked. (Imagine the time spent on fixing conflicts could be more than that)
Plus, I can exclude the implementation of flipper
which is a debugging tool included in future versions of react-native
.
Hand picking the lines makes me aware of the additional stuffs that are added (in this case, flipper
), and I am not including it this time.
Reason for doing so is to not have some extra dependencies or code to fix.
I just want to focus on the upgrade and I can live without the debug tool for now.
Since coming from 0.59.10
, I am using my other debugging tool, might as well not introduce uncertainties that will break the product.
I will give flipper
a try afterwards, but for now, the upgrade is in highest priority.
After applying the code changes (or if your are using the upgrade command). Run yarn install
(or npm install
depending on your setup.)
After installing the versions, if there are no errors. You are good to go to start build and run the project.
Assuming the new packages have no issues, you need to fix the build issues with you app and get it up and running like before.
The following are the issues that I've encountered and the solution to it. I always start debugging with iOS build with xcode. (Just a preference)
pod install
and bump into - ERROR | attributes: Missing required attribute
homepage.
Since 0.60.0
, native libraries are now auto linked. That means you don't have to specify the pod in your Podfile
anymore and React Native will pick that up. (some changes to Podfile
requires)
And for this reason, native libraries are required to have a .podspec
file for that to work.
If the homepage
are set to empty string s.homepage = ''
you will get this issue.
I am getting this issue for this package https://github.com/Aminoid/react-native-activity-recognition
The fix: Fork the repository and add a homepage to it. (There are another issue with this library's podspec, so forking the library is a better choice, more about this later)
CocoaPods could not find compatible versions for pod "React/Core":
This is a issue with react-native-image-crop-picker
library. Upgrading the library will fix it.
Since the dependency is now React-Core
.
YOUR_PROJECT_PATH/node_modules/react-native/React/Modules/RCTEventEmitter.h:8:9: 'React/RCTBridge.h' file not found
Got this issue for react-native-audio-recorder-player
. As you can tell, upgrading the library will fix it.
'React/RCTDefines.h' file not found
This one has to do with AppCenter
packages.
And the fix for this is well documented here.
<React/RCTBridgeModule.h> file not found
Now this is the real tricky part.
At this point, the header file is missing, and we are not sure, whether it is an error that only happens to this library only or all other libraries. For this, there is a way to inspect the issue.
This is very well written in this Github comment, so I am not going to elaborate futher.
https://github.com/facebook/react-native/issues/26665#issuecomment-571082076
In short, I have to remove the target.remove_from_project
from Podfile
post_install
then
pod deintegrate
pod cache clean
pod install
(not enough with just removing the Pods
directory)
and add the missing react back to scheme > build (for all the targets!)
Libraries
folder in xcode, all the .xcodeproj
and all the xxx.a
from Build Phases > Link Binary with Libraries
from native libraries if you haven't.Or use react-native unlink
(but again, I do it manually from xcode, because I don't want to unlink for android yet, as it turns out, android works without unlinking, but is is now redundant.)
Otherwise app will have duplicated headers from Pods and the Libraries projects.
MKTouchableManager.m:11:9: error: 'UIView+React.h' file not found with <angled> include; use "quotes" instead
Then I am having this issue with react-native-material-kit
. I use this for ranged slider with two thumbs. Looking for alternatives, but I am fixing this one first.
Turns out upgrading the project to the latest version fixed the issue.
No known class method for selector 'configure'
Then this issue, from firebase, basically I need to use firebase v6 instead of v5. Well, another breaking changes. Since local push notification are no longer usable in v6. I need to find solution for that. So in this case, upgrade to v6, and comment out implementation for local push notification and come back to this later. (Remember, we want to build and run the app and not spending too much time replacing the implementation and then we don't know why it is not working. Do one thing at a time. Complete the upgrade first.)
Upgrading to v6 has no much issues, also because the only thing that was in used with firebase is the local push notification. (but there are plans to use the Crashlytics, part of the reason why the upgrade is done)
And of course, the documentation on the website is great. I am using react-native-firebase
. (Sometimes the documentation update is so frequent that old documentation is not there anymore, so just keep up to date with the latest version as best as you can.)
At this point, the app can be built and run on simulator already.
Invariant Violation: Native module cannot be null.
and 'React/RCTEventEmitter.h' file not found
This is from the react-native-activity-recognition
library I am using. Second issue from the same library.
And it has to do with a incorrect path in podspec
being used. Before this I fixed it with importing the project to library and manually link the library code.
But now I need to use Podfile and this has to be fixed with updating the podspec
of the library.
Solution: Fork the repository, update the podspec
and install it in your app.
null is not an object (evaluating '_ReanimatedModule.default.createNode')
This has to do with react-native-tab-view
. Upgrade the react-native-tab-view
and react-native-reanimated
to the latest version.
Run pod install
for react-native-reanimated
to be updated.
Undefined is not an object (evaluating 'navigator.geolocation.getCurrentPosition')
navigator
is no longer available from the global object.
Install and use the it from https://github.com/react-native-community/react-native-geolocation
instead.
ViewPager
and ListView
If you are using libraries that depends on these APIs, you will need to upgrade the library as well. Or replace/remove the APIs in your app.
Cannot read property measureInWindow of undefined
Issue with react-navigation
v3. You will need to use v4 or v5.
From v3 to v4 has some minor changes. From v3 or v4 to v5 will have API changes. So upgrade with care.
For me, I opt to upgrade to v4 and still have some unexpected changes in behaviour. And need to fix it.
As you know, the local push notification is now broken, so I want to just stay with v4 to have less code that broken.
And when the app are back up to where, then I will consider upgrading to v5.
TypeError: Cannot call a class a function
This is a changes in the code that I wrote, it is now illegal to do that, I haven't investigated further whether the changes is from react-navigation
or react
library.
But I managed to figured out the issue.
Code with issue: (works with 0.59.10
)
headerLeft: NavHeader.Back,
Code changes after the upgrade:
headerLeft: props => <NavHeader.Back {...props} />
You should be able to tell what's wrong from the error description. (NavHeader
is a class component)
react-native-tab-view
Code with issue:
import { TabView, SceneMap, PagerPan } from 'react-native-tab-view';
Code changes:
import { TabView, SceneMap, ScrollPager as PagerPan } from 'react-native-tab-view';
However, even after the fix, the behaviour is not the same, therefore more work has to be done to disable animation and swipe on the tab.
AirGoogleMaps
dir must be added to your xCode project to support GoogleMaps on iOS.Upgrade the library and make sure to run pod install
Hopefully my writing can help you with the upgrade. Happy coding.
I will be writing up with the upgraded project next.