はじめに
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
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
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
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だし.それ以降のことはわからん・・・
解決するのにお世話になったサイト
修正した箇所は
- RootStackParamListを作成する
今回はtype.tsxファイルを別途作成し以下のコードを追記.
別ファイルなのでexportもやっておく.
export type RootStackParamList ={
Home: undefined;
Deteals: undefined;
}
- NavigatorにRootStackParamListを登録する
const HomeStack = createNativeStackNavigator<RootStackParamList>();
- Stack.Screenを使用していた箇所をHomeStackに変更する
<Stack.Navigator initialRouteName="Home">
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
- 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;
ヘッダーの編集
画面遷移時にヘッダーを指定するためには
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
を実行
わかんねぇかったよ・・迂闊にアップデートするもんじゃ無い