Open6

ReactNativeのNavigationOptionをTypeScriptでいい感じに使う

kenfdevkenfdev

NativeStackNavigatorの例。

import React from 'react';
import { Platform } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import CategoriesScreen from '../screens/CategoriesScreen';
import CategoryMealsScreen from '../screens/CategoryMealsScreen';
import MealDetailScreen from '../screens/MealDetailScreen';
import Colors from '../constants/Colors';
import { CATEGORIES } from '../data/dummy-data';

export type RootStackParamList = {
  Categories: undefined;
  CategoryMeals: { categoryId: string };
  MealDetail: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();

const MealsNavigator = () => (
  <NavigationContainer>
    <Stack.Navigator
      initialRouteName="Categories"
      screenOptions={{
        headerStyle: {
          backgroundColor: Platform.OS === 'android' ? Colors.primary : '',
        },
        headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
      }}
    >
      <Stack.Screen
        name="Categories"
        component={CategoriesScreen}
        options={{
          headerTitle: 'Meal Categories',
        }}
      />
      <Stack.Screen
        name="CategoryMeals"
        component={CategoryMealsScreen}
        options={(props) => ({
          title: CATEGORIES.find((c) => c.id === props.route.params.categoryId)
            ?.title,
        })}
      />
      <Stack.Screen name="MealDetail" component={MealDetailScreen} />
    </Stack.Navigator>
  </NavigationContainer>
);

export default MealsNavigator;
kenfdevkenfdev

他のScreenからいい感じに使えるようにするポイントはここ

export type RootStackParamList = {
  Categories: undefined;
  CategoryMeals: { categoryId: string };
  MealDetail: undefined;
};

他のScreenからはこうやって使える。ポイントは NativeStackScreenPropsRootStackParamList を渡してることと、第2引数に自分のScreen名を渡していること。これでルートパラメータも補完がきく。

interface Props
  extends NativeStackScreenProps<RootStackParamList, 'CategoryMeals'> {}

const CategoryMealsScreen: React.FunctionComponent<Props> = (props) => {
Challengy1Challengy1

詳細な情報ありがとうございます。この記事のお陰で物凄く助かりました。native-stack に関しては問題なく TypeScript 化できました。
ちょっと今困っているのは drawer の TypeScript 化で、下記の部分で TypeScript のエラーが出ます。

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={HomeScreen} />
        <Drawer.Screen name="Notifications" component={NotificationsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

上記で Drawer.Navigator が JSX として使えないと言うエラーが表示されます。

'Drawer.Navigator' cannot be used as a JSX component.

ただし、マトモに動くようで、TypeScript のエラー表示だけの問題です。
もし何か思い当たる節がございましたら、ご教授頂ければ幸いです。

Challengy1Challengy1

Package の中身を追いかけたのですが、どうもバグっぽいので、下記の issue を react navigation に上げておきました。
'Drawer.Navigator' cannot be used as a JSX component with TypeScript #10507

Challengy1Challengy1

速攻で reply をもらって、解決しました。原因は @types/react package が複数インストールされており、その内の一つを yarn remove して 上記の現象がなくなりました。因みに yarn why @types/react で調べて、yarn remove @types/react で消しました。只、@types/react を私が明示的にインストールした訳ではなく、React Native の環境を作る時に混在したようです。