wheatandcatの開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

React Navigation をv4→ v5にバージョンアップしてみた

こちらのPull Requestで諸々対応

■ react-navigation v5にアップデート
https://github.com/wheatandcat/Peperomia/pull/545/files

■ react-navigation v5のScreen optionにtypesを指定
https://github.com/wheatandcat/Peperomia/pull/549/files

概要

React Navigation v5はnpmのパッケージ自体を変更する大きな修正が入っています。 詳しくは以下のドキュメントを参照

reactnavigation.org

良くなったところ

ナビゲーションのgetParam、setParamsにTypeが指定できるようになった

reactnavigation.org

v4までだと画面遷移後にパラメータを引き渡すのにgetParam、 同画面内のheaderにパラメータを渡すのにsetParamsを使用していましたが、 v4まではここに対してtypeを指定できませんでしたが

■ v4 getParam

const kind = this.props.navigation.getParam('kind', null);

■ v4 setParam

const onDismiss = () => {
  this.setState({
   open: false,
  })
}

this.props.navigation.setParams({
  onDismiss,
});

v5からは各画面のScreen Optionsのtypeを指定できるようになりました。 指定の仕方は以下の各画面に書く画面のparamのtypeを指定して

■ src/lib/navigation.ts

export type RootStackParamList = {
  Main: undefined;
  Home: { refresh: boolean; onPushCreatePlan?: () => Promise<void> };
  CreatePlan: {
    date?: string;
    kind?: string;
  };
  AddScheduleDetail: {
    itemId?: string | number;
    kind?: string;
    priority?: number;
    onSave?: () => void;
  };
  Icons: {
    kind?: string;
    onSelectIcon?: (kind: string) => void;
    onDismiss?: () => void;
    photo?: boolean;
    defaultIcon?: boolean;
  };

以下のようにRootStackParamListから画面をしていてnavigation、routeにtypeを指定

import { RouteProp } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { RootStackParamList } from 'lib/navigation';

type ScreenNavigationProp = StackNavigationProp<RootStackParamList, 'Icons'>;
type ScreenRouteProp = RouteProp<RootStackParamList, 'Icons'>;

type Props = {
  navigation: ScreenNavigationProp;
  route: ScreenRouteProp;
};

すると、こんな感じで補完が効くようになります

f:id:wheatandcat:20200411145642p:plain:w400

ちなみにScreen Optionにtypeを指定する場合は、createStackNavigatorに指定すればOKです

import { createStackNavigator } from '@react-navigation/stack';
import { RootStackParamList } from 'lib/navigation';

const Stack = createStackNavigator<RootStackParamList>();

useRouteやuseNavigationを使用することでnavigationをpropsで引き回す必要はなくなった

import { useRoute } from '@react-navigation/native';

const Nav = memo((props: Props) => {
  const route = useRoute<ScreenRouteProp>();

  const kind = route.params?.kind;
import { useNavigation } from '@react-navigation/native';

const Nav = memo((props: Props) => {
  const { navigate } = useNavigation();

  const onPush = () => {
     navigate('Home')
  }
})

上記のようにuseRoute、useNavigationを使えば子コンポーネントに対してporpsで引き回さなくても画面遷移や画面のパラメータを取得できる

移行した感想

上記の紹介以外にもナビーゲーションの宣言がJSXになったり、 Modalの指定がNavigatorのmodeに移動したりありました。

破滅的な修正なので大きなプロジェクトでの移行は、結構時間がかかると思います。 ただ、ナビゲーションパラメータのところにtype指定できるようになったことで、ここの実装の気持ち悪さはかなり軽減されました。

次回はExpo SDK 37にアップデートする話を書く予定