typescript - איך להקליד נכון את useNavigation ב-React Navigation?
אני מנסה להקליד את useNavigation מ-React Navigation. אני רוצה להיות מסוגל להעביר רק את שם הנתיב, אבל אני מקבל שגיאה אלא אם כן אני גם מעביר props עבור הנתיב הזה.
לאחר קריאת התיעוד, אני מבין שהמימוש צריך להיראות משהו כזה:
import { StackNavigationProp } from '@react-navigation/stack';
type StackParamList = {
Home: { foo: string, onBar: () => void }
About: AboutProps
}
type NavigationProps = StackNavigationProp<StackParamList>
const MyComponent = () => {
const navigation = useNavigation<NavigationProps>()
const handleOnNavigate = () => navigation.navigate('Home')
// ^ TypeError!
אני מקבל TypeError בשורה האחרונה שם. אם אני מוסיף את ה-props עבור הנתיב הזה, השגיאה נעלמת, אבל לא אמור להיות עלי לעשות את זה.
navigation.navigate('Home', { foo: 'hello', onBar: () => {} })
כאשר מסתכלים על הצהרת הסוג עבור navigation.navigate (ראה למטה), זה לא אמור להיות נחוץ, מכיוון שיש עודף צורה שמאפשר פשוט להעביר את שם הנתיב כטיעון יחיד. אני בטח עושה משהו לא נכון, מכיוון שזה לא מתקבל ... אבל מה, איפה ולמה?
הנה CodeSandBox שמתרחשת בו TypeError.
סוגי React Navigation.d.ts (קישור)
navigate<RouteName extends keyof ParamList>(...args: undefined extends ParamList[RouteName]
? [screen: RouteName] | [screen: RouteName, params: ParamList[RouteName]]
: [screen: RouteName, params: ParamList[RouteName]])
: void;
תשובה #1
כאשר משתמשים ב-Typescript, כל הניווט צריך להיות מוקלד באופן קפדני. למרבה המזל, איננו צריכים לכתוב עטיפות עבור היישומים שלהם, מכיוון שסופקו לנו סוגים כלליים.
הדרך הפשוטה ביותר שמצאתי להוסיף טיפוסים ל-hook של useNavigation היא הבאה:
יש לשנות את מימוש סוג
RootStackParamListאם הנתיב שלך מקבל פרמטרים
// src/_app.tsx
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import HomeScreen from "./screens/home";
import AuthScreen from "./screens/auth";
export type ScreenNames = ["Home", "Auth"] // type these manually
export type RootStackParamList = Record<ScreenNames[number], undefined>;
export type StackNavigation = NavigationProp<RootStackParamList>;
const Stack = createNativeStackNavigator<RootStackParamList>();
export const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Auth" component={AuthScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
// src/screens/home.tsx
import { useNavigation } from '@react-navigation/native';
import { type StackNavigation } from "../_app";
const HomeScreen = () => {
const { navigate } = useNavigation<StackNavigation>();
const handleOnNavigate = () => navigate("Home");
// ... the rest of the component code
}
export default HomeScreen;
שים לב גם שהם לא משתמשים ב-hook useNavigation עבור עמודים/מסכים, אלא עבור קומפוננטים שממוקמים עמוק בתוך העץ, כי הניווט כבר מועבר כ-prop לקומפוננטים שמועברים ל-Stack.Screen, כלומר אתה יכול גם להשתמש בניווט של HomeScreen בצורה הבאה:
// src/screens/home.tsx
import { type StackNavigation } from "../_app";
interface HomeScreenProps {
navigation: StackNavigation;
}
const HomeScreen: React.FC<HomeScreenProps> = ({ navigation }) => {
const handleOnNavigate = () => navigation.navigate("Home");
// ... the rest of the component code
}
export default HomeScreen;
תשובה #2
import { useNavigation, ParamListBase, NavigationProp } from '@react-navigation/native';
const navigation: NavigationProp<ParamListBase> = useNavigation();
כל מה שאתה צריך לעשות הוא לייבא את ה-hook, הפרופ והסוג הנדרשים ופשוט ליישם כמו שנראה במעלה בדוגמה. לחיים 👋
