The UpgradeJS Blog

Case Study: Upgrading React Native from Version 0.59 to 0.71

In this blog post, I initially intended to discuss upgrading React Native opens a new window applications using the “backwards-compatible opens a new window ” approach. However, I discovered an opportunity to explore another interesting topic: An upgrade regenerating the project.

Join me as we dive into a case study where I successfully upgrade a React Native iOS-targeted application from version 0.59 all the way to the latest version, 0.71 opens a new window !

Upgrade strategy

There are several strategies opens a new window to consider when upgrading a React Native application. A prerequisite for all of them is having an application that can be run locally and works as expected.

In my case, I had a 4-year-old application. My first attempt involved starting the React Native server (Metro opens a new window ) by running the react-native start command.

After that, I proceeded to build the development version of the application in Xcode.

The server started successfully but the build failed. The error occurred in one of the modules, and the message that I saw was this one:

Cannot initialize a parameter of type 'NSArray<id<RCTBridgeModule>> *' with an rvalue of type 'NSArray<Class> *'

After spending some time searching for the cause and solution to this issue, I discovered several comments under issues in the React Native GitHub project opens a new window .

Most of these comments suggested modifying the native code.

I tried a couple of solutions, but the most common one opens a new window didn’t work for me. Another solution opens a new window fixed the initial problem.

Then several new issues emerged right after.

These new problems were related to the syntax of the native modules being used. So, I decided to create a new project using React Native CLI opens a new window and build the application to see if the newer version would have the same issues.

To create and open a project in Xcode, I executed the following commands:

npx react-native@latest init ProjectForTest

cd ProjectForTest

xed -b ios

After that, I simply clicked the Run button in Xcode, and my project was built and started successfully.

After seeing this result, I realized that I could attempt to update the application to the latest version of React Native by copying portions of the project that aren’t part of the React Native template.

I reached this conclusion because, in my original project, I hardly added any extra code or resources to the ios folder, aside from permission configurations and assets like icons.

The upgrade

After inspecting the project, I found that only two non-native components needed to be copied into the new project:

  • The src folder which contains all the source code
  • The package.json file which lists the dependencies

While merging the package.json files, I encountered a few overlapping dependency versions. Notably, two of them were react and react-native, with the rest being a set of devDependencies. I decided to adopt the newer versions for all of these dependencies.

It is important to note that React Native v0.71 requires version 18.2 of React. We have an article on how to upgrade to the latest version of React from versions 16.x and 17.x opens a new window .

After reinstalling the modules, I tried to run the project again. Unfortunately, I wasn’t lucky enough to achieve the desired result on my first attempt.

Picker

I encountered an error screen displaying a message that might require significant changes to the application. The error indicated that the Picker opens a new window component had been removed from the react-native opens a new window package.

An error message about the removed Picker component from React Native

Upon further inspection, I discovered that this component wasn’t used directly in the application, but rather by another module. This made the situation even more frustrating.

The library that utilized the Picker component was react-native-picker-select opens a new window . The next step involved inspecting the library to determine if this migration had been addressed in newer versions.

As the changes were handled in version 8.0.0 opens a new window I thought I could simply upgrade that dependency to solve the problem.

However, the installation steps had changed, so it was not sufficient to simply upgrade the version of that dependency. It was also necessary to install @react-native-picker/picker opens a new window as an additional dependency.

After restarting the application with these dependencies in place, the initial error was resolved, but another error came up.

react-native-screens

I encountered an error involving an unresolvable dependency - react-native-screens opens a new window . This dependency was required by one of the components in react-navigation-tabs opens a new window , which is a sub-project of react-navigation opens a new window used for building the app’s navigation.

To resolve this issue, I examined the installed react-navigation-tabs module and discovered that it had a peer dependency: "react-native-screens": "^1.0.0 || ^1.0.0-alpha" which had not been installed for some reason.

I attempted to install it by running yarn add react-native-screens@^1.0.0, but this command informed me that the specified version did not exist. However, it did provide a list of available options, from which I identified a few versions like 1.0.0-alpha.

I selected version 1.0.0-alpha.23, installed it, and then ran the npx pod-install command. After completing these steps, executing the react-native run-ios command led me to a third error.

@react-native-community/netinfo

After reading the third error message, I felt much more confident about how to proceed in this case. The error message was related to an unresolvable dependency.

This time, the dependency in question was @react-native-community/netinfo, and the module it was being called from was react-native-offline opens a new window .

To resolve this issue, I followed the same process described in the previous section.

Upon completing all the steps, the first screen of the application finally appeared! After conducting manual testing, I discovered that all parts of the application were functioning correctly, and the UI matched the original version.

Further steps

My primary task was complete, but there was still one dependency that required upgrading: react-navigation. I decided to attempt upgrading it.

React Navigation has excellent documentation and helpful migration guides opens a new window .

The original version of react-navigation in the project was 3.8.1. I began by reading the migration guides for each version and discovered that I could minimize the number of steps by jumping directly to version 6.x.

Here’s a look at a portion of the original navigation configuration:

const SearchStackNavigator = createStackNavigator(
 {
  Search: {
   screen: (props: NavigationComponent) =>
    ScreenWithLayout(props, MainLayout, SearchScreen),
  },
  Results: {
   screen: (props: NavigationComponent) =>
    ScreenWithLayout(props, MainLayout, ResultsScreen),
  },
 },
 {
  headerMode: 'none',
 },
);

After completing all the installation steps opens a new window and modifying the codebase, I ended up with this version of the code:

function SearchStack() {
  return (
    <SearchStackNavigator.Navigator
      screenOptions=>
      <SearchStackNavigator.Screen name="Search">
        {props => ScreenWithLayout(props, MainLayout, SearchScreen)}
      </SearchStackNavigator.Screen>
      <SearchStackNavigator.Screen name="Results">
        {props => ScreenWithLayout(props, MainLayout, ResultsScreen)}
      </SearchStackNavigator.Screen>
    </SearchStackNavigator.Navigator>
  );
}

Important notes

One crucial step that can save significant time during the upgrade opens a new window process is running the npx pod-install command to update the iOS native modules after installing or removing a dependency.

To prevent false negatives or positives, it’s recommended to clear the cache and builds opens a new window before initiating a new attempt. You can even temporarily modify your start script by adding the –reset-cache tag during the upgrade process.

As general advice, always review the release notes, CHANGELOG.md, and README.md of the desired modules before upgrading. This step will simplify the upgrade process by familiarizing you with any changes, especially breaking changes in the newer versions.

Extra

Below is the original configuration found in the package.json file:

"dependencies": {
   "bugsnag-react-native": "^2.17.1",
   "native-base": "^2.12.1",
   "react": "16.8.3",
   "react-native": "0.59.5",
   "react-native-datepicker": "^1.7.2",
   "react-native-gesture-handler": "^1.1.0",
   "react-native-keyboard-aware-scroll-view": "^0.8.0",
   "react-native-offline": "^4.3.1",
   "react-native-picker-select": "^6.1.0",
   "react-navigation": "^3.8.1",
   "redux-saga": "^1.0.2",
   "reselect": "^4.0.0",
   "styled-components": "^4.2.0"
},
"devDependencies": {
   "@babel/core": "^7.4.3",
   "@babel/runtime": "^7.4.3",
   "@types/axios": "^0.14.0",
   "@types/jest": "^24.0.11",
   "@types/node": "^11.13.7",
   "@types/react": "^16.8.14",
   "@types/react-native": "^0.57.47",
   "@types/react-native-datepicker": "^1.7.0",
   "@types/react-navigation": "^3.0.6",
   "@types/react-redux": "^7.0.8",
   "@types/react-test-renderer": "^16.8.1",
   "@types/redux": "^3.6.0",
   "@types/redux-saga": "^0.10.5",
   "@types/reselect": "^2.2.0",
   "@types/styled-components": "^4.1.14",
   "axios": "^0.18.0",
   "babel-jest": "^24.7.1",
   "jest": "^24.7.1",
   "metro-react-native-babel-preset": "^0.53.1",
   "react-redux": "^7.0.3",
   "react-test-renderer": "16.8.3",
   "redux": "^4.0.1",
   "typescript": "^3.4.4"
}

After upgrading, the first working configuration was as follows:

"dependencies": {
 "@react-native-community/netinfo": "^6",
 "@react-native-picker/picker": "^2.4.10",
 "axios": "^0.18.0",
 "bugsnag-react-native": "^2.17.1",
 "react": "^18.2.0",
 "react-native": "0.71.7",
 "react-native-datepicker": "^1.7.2",
 "react-native-gesture-handler": "^1.1.0",
 "react-native-keyboard-aware-scroll-view": "^0.9.5",
 "react-native-offline": "^6.0.2",
 "react-native-picker-select": "^8.0.4",
 "react-native-screens": "^1.0.0-alpha.23",
 "react-navigation": "^3.8.1",
 "react-redux": "^7.0.3",
 "redux": "^4.0.1",
 "redux-saga": "^1.0.2",
 "reselect": "^4.0.0",
 "styled-components": "^4.2.0"
},
"devDependencies": {
 "@babel/core": "^7.20.0",
 "@babel/preset-env": "^7.20.0",
 "@babel/runtime": "^7.20.0",
 "@react-native-community/eslint-config": "^3.2.0",
 "@tsconfig/react-native": "^2.0.2",
 "@types/axios": "^0.14.0",
 "@types/jest": "^29.2.1",
 "@types/node": "^11.13.7",
 "@types/react": "^18.2.2",
 "@types/react-native": "^0.57.47",
 "@types/react-native-datepicker": "^1.7.0",
 "@types/react-redux": "^7.0.8",
 "@types/react-test-renderer": "17.0.2",
 "@types/redux": "^3.6.0",
 "@types/redux-saga": "^0.10.5",
 "@types/reselect": "^2.2.0",
 "@types/styled-components": "^4.1.14",
 "babel-jest": "^29.2.1",
 "eslint": "^8.19.0",
 "jest": "^29.2.1",
 "metro-react-native-babel-preset": "0.73.9",
 "prettier": "^2.4.1",
 "react-test-renderer": "^18.2.0",
 "typescript": "4.8.4"
}

Conclusion

In conclusion, the less common upgrade approach of updating a React Native application directly from version 0.59 to 0.71 proved to be a viable and efficient method for this application.

By creating a new project with the latest React Native version and gradually integrating the custom code and resources from the old project, I successfully upgraded the application without the need for tedious modifications of the native code.

This case study serves as a valuable example for developers looking to upgrade their React Native applications to the latest versions, demonstrating that a direct upgrade can indeed be a practical and effective strategy.

While this approach may not be suitable for every situation, it is worth considering if you are facing similar challenges with older React Native projects and your application is small enough.

If your React Native application is quite large and you don’t have a reliable test suite, we recommend that you upgrade your application one major version at a time.

Need help upgrading your React Native opens a new window application? We specialize in upgrading JavaScript applications opens a new window ! Contact us! opens a new window