ReactNative は 0.63.2
まで更新してある状態で、React Navigationのバージョンを4系から5系にバージョンアップしました。
その時の対応をまとめます。
React Navigation 5のアップデート内容
下記にまとまっています。
ここで取り上げられているテーマは下記の通り
- React コンポーネントを使った設定
- 新しいフック
- コンポーネントからのオプションの更新
- 新しいテーマAPI
- TypeScript化(型を第一級に扱う)
- Redux DevTools との統合
- ネイティブなStack Navigator
- ネイティブなMaterial top tab navigator
npm packageの更新
https://reactnavigation.org/docs/upgrading-from-4.x#package-names
使っていたライブラリについて、下記のように変更
react-navigation -> @react-navigation/native react-navigation-stack -> @react-navigation/stack react-navigation-tabs -> @react-navigation/bottom-tabs
@react-navigation/material-top-tabs
と @react-navigation/material-bottom-tabs
は今のプロジェクトでは不要だったのでインストールしませんでした。
また、v4との互換性を保つための仕組みを提供してくれる @react-navigation/compat
を使いました。
=> 最終的に使うのをやめました。
バージョンアップの方針
下記に4系からのアップデートについての方法が公式ページにあります。
Upgrading from 4.x | React Navigation
ここでもある通り、React Navigation 4
のメンテナンスは当面は継続して行い、React Native
の最新バージョンにも追従すると書かれています。
いつまでメンテしてくれるかはなんか不安ですが、今すぐに開発が止まるということがなさそうなので、すぐに無理にバージョンアップしなくてもよさそうです。
今のプロジェクトではアップデートする時間を作れたのでアップデートを実施しました。
@react-navigation/compat
を使う @react-navigation/compatは使わずにアップデートしました
@react-navigation/compat
を使うReact Navigation 5では4とはほぼ互換性がない状態です。
なので、いきなり全部対応しようとすると量が膨大になるので、まずはReact Navigationが用意した @react-navigation/compat
を利用し、変更を最小限にしました。
今後の運用も考えて @react-navigation/compat
は使わずにアップデートを行いました。
変更箇所
createStackNavigator
createBottomTabNavigator
を使ったNagvigator
v5での createXNavigator
は 大幅に変更されており、React コンポーネントとしてnavigatorを設定するようになっています。
https://reactnavigation.org/docs/upgrading-from-4.x/#configuring-the-navigator
createStackNavigator | React Navigation
なので、ここは一旦 @react-navigation/compat
の createCompatNavigatorFactory
を使って既存の呼び出しをラップしました。
Navigatorの数が少なかったのと今後の運用を加味して、v5の方式に移行しました。
v5ではScreenで柔軟にオプションを指定できるようになったため、同時にNavigatorの階層を見直し階層を減らしています。
下記に書いてあるとおり、今回のアップデートではかなり大きな方針変更がありました。
https://reactnavigation.org/docs/nesting-navigators/#navigating-to-a-screen-in-a-nested-navigator
v4以前では、遷移は静的に定義されていたのに対し、v5では動的に設定されるようになりました。
v4以前では、再帰的にScreenを探しにいきますが、v5ではそれがなくなりました。
v5では、現在のNavigator内で遷移できなければ、一階層上の親のNavigatorから探しに行きますが、それより上には行けないようです。
そのため、Navigatorの階層は2つくらいに抑えることが推奨されています。
When nesting multiple stack navigators, we recommend nesting at most 2 stack navigators, unless absolutely necessary.
Nesting navigators | React Navigation
createSwitchNavigator
は @react-navigation/compat
のものを使う createSwitchNavigatorは利用をやめました
createSwitchNavigator
は @react-navigation/compat
のものを使うReact Navigation 5
では、React コンポーネントを使うようになったため、条件分岐なども書けるようになりました。
そのため、NavigatorのScreen定義を、動的に定義して変更することができるので、Switch Navigatorが不要になります。
なので、createSwitchNavigator
は廃止されているのですが、 今回修正範囲が大きかったので、一旦 @react-navigation/compat
にある、createSwitchNavigator
を使いました。
それに従い、 createStackNavigator
に置き換えて対応しました。
NavigationStackScreenProps
を StackNavigationProp
に置き換える
v5では NavigationStackScreenProps
は StackNavigationProp
となりました。
v4
https://reactnavigation.org/docs/4.x/typescript/#type-checking-all-props-for-a-screen
v5
https://reactnavigation.org/docs/typescript/#type-checking-screens
これにより、Screenに対するparameterを型チェックできるようになります。
修正はこんな感じでした。
navigation.navigate
を使った遷移にも型チェックが効くようになっています。
下記のような感じで全般的に書き直しました。
Screen名 + ParamList というtypeを用意しつつ、exportしています。
import { BarParamList } from 'src/screens/Bar' export type FooParamList = { Foo: {} } interface Props { navigation: StackNavigationProp<FooParamList & BarParamList> } export function Foo({ navigation }: Props) { useEffect(() => { if (!isLoading && isLoggedIn) { navigation.navigate('Bar', {}) } }, [isLoading, isLoggedIn, navigation]) return ( <Wrapper> <FooContent /> </Wrapper> ) }
useNavigation
は @react-navigation/native
のものを使う
これはimportの変更のみです。
-import { useNavigation } from 'react-navigation-hooks' +import { useNavigation } from '@react-navigation/native'
Sceenには前のScreenから navigationとrouteを受け取るようになりました。
https://reactnavigation.org/docs/params#passing-params-to-a-previous-screen
そのため、Screenでは useNavigation
を使わず、渡ってくるnavigationを使うようにしました。
パラメーターの受け渡しの変更、 getParam
の廃止
https://reactnavigation.org/docs/upgrading-from-4.x/#the-navigation-prop
React Navigation 5
では、navigation
propは2つのpropに分割されています。
navigation
prop :navigate
やgoBack
などのヘルパーメソッドを含むroute
prop : 現在の画面のデータを含みます。 これは 4とかだとnavigation.state
を使っていたものです。
また、getParam
は廃止されました。
getParam
は主に2つの役割がありました。
params
がundefined
になることを防ぐparams.someParam
が未定義または null であった場合においてデフォルト値を設定する
これらは、TypeScriptの optional chaining
と nullish coalescing operators
で同等のことができます。
Passing parameters to routes | React Navigation
v5ではこのようになりました。
export function Foo({ route, navigation }: Props) { const uniqueKey = route.params.uniqueKey return ( <ScrollView> <Block> <FooContetn uniqueKey={uniqueKey} /> </Block> </ScrollView> ) }
createAppContainer
から NavigationContainer
を使うように変更
React Navigation 5
では createAppContainer
は廃止されました。
下記のドキュメントのように、NavigationContainer
を使うように修正しただけでした。
https://reactnavigation.org/docs/upgrading-from-4.x#navigation-container
参考資料
Upgrading from 4.x | React Navigation
Compatibility layer | React Navigation
Passing parameters to routes | React Navigation