2
1

More than 1 year has passed since last update.

React Navigationを使ってみる

Posted at

はじめに

react navigationを使うならreact nativeは使わない手はないと感じたので学んで行こうかなと思います.
我流でやっていくとよくわからない罠にハマることが多かった過去があるので,公式のやり方を学んでいこうかと思います.

動作環境

ProductName: macOS
ProductVersion: 11.7.2
BuildVersion: 20G1020

expo: 6.1.0

"@react-navigation/bottom-tabs": "^6.0.5",
"@react-navigation/native": "^6.0.2",
"@react-navigation/native-stack": "^6.1.0",

参考にしたサイト

react navigation公式
expo のtabテンプレート
【React Native入門】React Navigation(画面移動)の設定方法を理解する

やることまとめ

全体

パッケージのインストール

npx expo install @react-navigation/native

Stack

パッケージのインストール

npx expo install @react-navigation/native-stack
app.tsx
export type RootStackParamList = {
    Stack1: { Stack1Moji: string };
    Stack2: undefined;
};

export type RootStackScreenProps<Screen extends keyof RootStackParamList> =
    NativeStackScreenProps<RootStackParamList, Screen>;

const Stack = createNativeStackNavigator<RootStackParamList>();
function Stacks() {
    return (
        <Stack.Navigator>
            <Stack.Screen
                name="Stack1"
                component={Stack1Screen}
                options={({ route }) => ({
                    title: route.params
                        ? "Stack1-" + route.params.Stack1Moji
                        : "Stack1-undifine",
                })}
            />
            <Stack.Group screenOptions={{ presentation: "modal" }}>
                <Stack.Screen name="Stack2" component={Stack2Screen} />
            </Stack.Group>
        </Stack.Navigator>
    );
}

function Stack1Screen({ route, navigation }: RootStackScreenProps<"Stack1">) {
    return (
        <View
            style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
        >
            <Text>Stack1Screen</Text>
            <Text>moji: {route.params?.Stack1Moji}</Text>
            <Button
                title="Go Stack2"
                onPress={() => navigation.navigate("Stack2")}
            />
        </View>
    );
}

function Stack2Screen({ navigation }: RootStackScreenProps<"Stack2">) {
    const [enterdMoji, setEnterdMoji] = React.useState("");
    return (
        <View
            style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
        >
            <Text>Stack2Screen</Text>
            <Button title="Go back" onPress={() => navigation.goBack()} />
            <TextInput
                multiline
                placeholder="What's on your mind?"
                style={{ height: 200, padding: 10, backgroundColor: "white" }}
                value={enterdMoji}
                onChangeText={setEnterdMoji}
            />
            <Button
                title="Done"
                onPress={() => {
                    navigation.navigate("Stack1", { Stack1Moji: enterdMoji });
                }}
            />
        </View>
    );
}

Tab

パッケージのインストール

npx expo install @react-navigation/bottom-tabs
ts; app.tsx
export type RootTabParamList = {
    Tab1: undefined;
    Tab2: { tab2Moji: string | null };
};

export type RootTabScreenProps<Screen extends keyof RootTabParamList> =
    CompositeScreenProps<
        BottomTabScreenProps<RootTabParamList, Screen>,
        NativeStackScreenProps<RootStackParamList>
    >;

const Tab = createBottomTabNavigator<RootTabParamList>();

function Tabs() {
    return (
        <Tab.Navigator>
            <Tab.Screen name="Tab1" component={Tab1Screen} />
            <Tab.Screen name="Tab2" component={Stacks} />
        </Tab.Navigator>
    );
}

drawer

## ドローワー使う時に必要
npx expo install @react-navigation/drawer react-native-reanimated
## ドローワーを使うのにbabel.config.jsを修正
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: ['react-native-reanimated/plugin'],
  };
};
## クリアも忘れずに
npx expo start --clear
app.tsx
export type RootDrawerParamList = {
    Drawer1: undefined;
    Drawer2: { Drawer2Moji: string | null };
};

const Drawer = createDrawerNavigator<RootDrawerParamList>();

function Drawers() {
    return (
        <Drawer.Navigator>
            <Drawer.Screen name="Drawer1" component={TemplateScreen} />
            <Drawer.Screen name="Drawer2" component={Tabs} />
        </Drawer.Navigator>
    );
}

1

試行錯誤

画面遷移

参考サイト:Moving between screens

この部分で詰まった
エラー内容
バインド要素 'navigation' には暗黙的に 'any' 型が含まれます。ts(7031)

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>

引数のnavigationの型がちゃんとしてないんだろう.TypeScriptだし.それ以降のことはわからん・・・

解決するのにお世話になったサイト

修正した箇所は

  1. RootStackParamListを作成する
    今回はtype.tsxファイルを別途作成し以下のコードを追記.
    別ファイルなのでexportもやっておく.
export type RootStackParamList ={
    Home: undefined;
    Deteals: undefined;
}
  1. NavigatorにRootStackParamListを登録する
const HomeStack = createNativeStackNavigator<RootStackParamList>();
  1. Stack.Screenを使用していた箇所をHomeStackに変更する
      <Stack.Navigator initialRouteName="Home">
        <HomeStack.Screen name="Home" component={HomeScreen} />
        <HomeStack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>

  1. Screenにnavigationの追加
    const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, "Home">>();

この"Home"ってなんぞや?
自信のスクリーン名なのか?親のスクリーン名なのか?

変数を渡す

この部分で怒られた.
Detailsの引数が指定されていないのでしょう.

navigation.navigate("Details", {
    itemId: 86,
    otherParam: "anything you want here",
});

ここに対処法がありました.
RootStackのDetailsに型宣言します.

export type RootStackParamList = {
    Home: undefined;
    Details: { itemId: number; otherParam: string };
};

DetailsScreenに引数を指定して型宣言をする.
パラメータはroute.paramsで取得する.

function DetailsScreen({ route, navigation }: DetailsProps) {
    const { itemId, otherParam } = route.params;

ヘッダーの編集

Configuring the header bar

画面遷移時にヘッダーを指定するためには
ProfileスクリーンにHomeスクリーンから移動するためのボタンを追加.
この時に引数にパラメータを渡す

<Button
    title="Go to Profile"
    onPress={() =>
        navigation.navigate("Profile", {
            name: "Home -> Profile",
        })
    }
/>

Profileスクリーン情報をナビゲータに登録する

<HomeStack.Screen
    name="Profile"
    component={ProfileScreen}
    options={({ route }) => ({ title: route.params.name })}
/>

TypeScriptだと引数が判定できないということで

export type RootStackParamList = {
    Home: { post: string };
    CreatePost: undefined;
    Details: { itemId: number; otherParam: string };
    Profile: { name: string };
};

export type ProfileProps = NativeStackScreenProps<
    RootStackParamList,
    "Profile"
>;

を追加

自身のスクリーンのタイトルを変更するにはProfileScreenでnavigation.setOptionsを使用して変更する

<Button
    title="Update the title"
    onPress={() => navigation.setOptions({ title: "Updated!" })}
/>

drawerが起動できない

EXPO SDK のバージョンが47.0.xにアップデートしたらdrawerが使えなくなっていた.

こちらのサイトを参考にしてプロジェクトを作成して
こちらのサイトのbabel設定したら動いた

module.exports = function (api) {
    api.cache(true);
    return {
        presets: ["babel-preset-expo"],
        plugins: ["react-native-reanimated/plugin"],
    };
};

babel.config.jsを↑に変更して

npx expo start --clear

を実行
わかんねぇかったよ・・迂闊にアップデートするもんじゃ無い

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1