React Native - 0.60


  1. https://facebook.github.io/react-native/blog/2019/07/03/version-60
  2. https://github.com/react-native-community/releases/blob/master/CHANGELOG.md#060

[iOS and Android] CLI autolinking

  1. https://github.com/react-native-community/cli/blob/master/docs/autolinking.md

https://facebook.github.io/react-native/blog/2019/07/03/version-60#native-modules-are-now-autolinked

The team working on the React Native CLI has introduced major improvements to native module linking called autolinking! Most scenarios will not require the use of react-native link anymore. At the same time, the team overhauled the linking process in general. Be sure to react-native unlink any preexisting dependencies as mentioned in the docs above.

=> now there’s no need to link libraries manually - it’s done automatically when building application.

for iOS remove all application pods from ios/Podfile (BVLinearGradient, Picker, RNCAsyncStorage, etc.) and run pod install - these RN module pods must be detected automatically.

however this is not the case with OneSignalNotificationServiceExtension extension - I still had to link it manually in Xcode (select corresponding target and add libRCTOneSignal.a in Link Binary With Libraries section).

not all packages support autolinking - first of all this concerns outdated packages which haven’t been updated for a while. in case of iOS they might have no podspec => link such packages as usual - using react-native link:

$ react-native link react-native-admob

[Android] AndroidX

https://medium.com/@yathousen/the-day-google-decided-to-shake-the-react-native-community-4ba5cdd33388

It was June 17th, 2019, Android released their new package names for their DEPRECATED support libraries + other tools inside AndroidX…

Basically, all of the basic libraries that Google provide for the Android + React Native Community, on the last or close to last versions were affected. In some cases, it was the fault of the react-native libraries maintainers for using imports like + symbols that are ambiguous and generally take the last version available of the library and in some other cases was caused by the fact that the developer was actually using new features from the latest release.

https://stackoverflow.com/a/52517772/3632318

AndroidX is redesigned library to make package names more clear.

https://developer.android.com/jetpack/androidx/

AndroidX is a major improvement to the original Android Support Library.

AndroidX fully replaces the Support Library by providing feature parity and new libraries.

https://developer.android.com/jetpack/androidx/migrate

AndroidX replaces the original support library APIs with packages in the androidx namespace. Only the package and Maven artifact names changed; class, method, and field names did not change.

https://stackoverflow.com/a/54533702/3632318

One app should use either AndroidX or old Android Support libraries. That’s why you faced this issue.

So the solution is to use either AndroidX or old Support Library.

so the problem is that application might be using both new AndroidX and old Android Support libraries which is not allowed.

it’s possible to examine all application dependencies using this command:

$ cd android
$ ./gradlew app:dependencies

AFAIU there must be either com.android.support or androidx.* libraries in the output but not both.

the reason why AndroidX libraries leak into current application dependencies is that many RN libraries use the latest versions of Google libraries instead of specific ones, say (note + symbol):

// https://github.com/zo0r/react-native-push-notification/blob/c4c961cf3a76bffe4e9e36cf00201611eecbb898/android/build.gradle

dependencies {
    // ...
    implementation "com.google.android.gms:play-services-gcm:${safeExtGet('googlePlayServicesVersion', '+')}"
    // ...
    implementation "com.google.firebase:firebase-messaging:${safeExtGet('firebaseVersion', '+')}"
}

but the latest versions of Google started to depend on AndroidX libraries since June 17th, 2019 and it was a breaking change.

there are 2 approaches to solve this problem:

use Android Support Libraries only

in most cases it’s just necessary to use specific versions of Google libraries which don’t depend on AndroidX libraries.

this can be enforced in several ways:

migrate everything to AndroidX

  1. https://facebook.github.io/react-native/blog/2019/07/03/version-60#androidx-support
  2. https://github.com/react-native-community/react-native-camera/blob/master/docs/AndroidXMigration.md

deprecated lifecycle hooks

https://stackoverflow.com/a/51981144/3632318

componentWillReceiveProps is a synchronous hook. Calling asynchronous function like data fetching inside this hook will need to render in between when the new props are set and when data has finished loading.

Which won’t give you unnecessary renders. Note that getDerivedStateFromProps is used only in rare case though. So, I suggest you to use componentDidUpdate hook as far as possible.

The similar things happen when comparing componentWillMount and componentDidMount. Use componentDidMount whenever you need operate async operation and forget componentWillMount at all condition.

componentWillReceiveProps

  1. https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

https://reactjs.org/docs/react-component.html#componentdidupdate

You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you’ll cause an infinite loop.

https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#side-effects-on-props-change

Instead, the componentDidUpdate lifecycle should be used since it is guaranteed to be invoked only once per update

- componentWillReceiveProps(nextProps) {
-   if (nextProps.gamer !== this.props.gamer) {
-     this.setState({comment: nextProps.gamer.game_comment});
+ componentDidUpdate(prevProps) {
+   if (this.props.gamer !== prevProps.gamer) {
+     this.setState({comment: this.props.gamer.game_comment});
    }
  }

componentWillMount

https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#fetching-external-data

There is a common misconception that fetching in componentWillMount lets you avoid the first empty rendering state. In practice this was never true because React has always executed render immediately after componentWillMount. If the data is not available by the time componentWillMount fires, the first render will still show a loading state regardless of where you initiate the fetch. This is why moving the fetch to componentDidMount has no perceptible effect in the vast majority of cases.

- componentWillMount() {
+ componentDidMount() {
    this.props.getGameStat().catch(AlertHelpers.serverError);
  }