Loading...
Loading...
Compare original and translation side by side
Quick Guide: Use the static API for simpler TypeScript inference and automatic deep linking config. Use the dynamic API when you need runtime-dynamic screen lists. Always declare a globalfor type-safeRootParamListeverywhere. UseuseNavigation(not the JS stack) for production performance. Auth flows use conditional screen rendering via thecreateNativeStackNavigatorcallback (static) or conditional JSX (dynamic). Deep linking config lives per-screen in the static API -- no separate config object needed.if
快速指南: 静态API适用于更简洁的TypeScript类型推断和自动深度链接配置。当你需要运行时动态屏幕列表时,使用动态API。务必声明全局,让所有地方的RootParamList都具备类型安全性。生产环境中使用useNavigation(而非JS栈)以保证性能。认证流程通过createNativeStackNavigator回调(静态API)或条件JSX(动态API)实现条件屏幕渲染。静态API中,深度链接配置在每个屏幕中定义——无需单独的配置对象。if
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,, named constants)import type
ReactNavigation.RootParamListuseNavigationcreateNativeStackNavigator@react-navigation/stackpopTo()navigate()useFocusEffectuseCallbacknavigation.navigate('NestedScreen')RootParamListiflinkingnavigation.preload()useFocusEffectusePreventRemove所有代码必须遵循CLAUDE.md中的项目约定(短横线命名、命名导出、导入顺序、、命名常量)import type
ReactNavigation.RootParamListuseNavigationcreateNativeStackNavigator@react-navigation/stackpopTo()navigate()useFocusEffectuseCallbacknavigation.navigate('NestedScreen')RootParamListiflinkingnavigation.preload()useFocusEffectusePreventRemove<Stack.Navigator><Stack.Screen>createNativeStackNavigator@react-navigation/stackReactNavigation.RootParamListuseNavigation()useFocusEffectuseEffectnavigate()popTo()headerBackTitleVisibleheaderBackButtonDisplayModefonts<Stack.Navigator><Stack.Screen>createNativeStackNavigator@react-navigation/stackReactNavigation.RootParamListuseNavigation()useFocusEffectuseEffectnavigate()popTo()headerBackTitleVisibleheaderBackButtonDisplayModefontsimport { createStaticNavigation } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import type { StaticParamList } from "@react-navigation/native";
const RootStack = createNativeStackNavigator({
initialRouteName: "Home",
screenOptions: { headerShown: true },
screens: {
Home: HomeScreen,
Profile: {
screen: ProfileScreen,
linking: "profile/:userId",
},
},
});
const Navigation = createStaticNavigation(RootStack);
// Declare global types -- makes useNavigation() type-safe everywhere
type RootStackParamList = StaticParamList<typeof RootStack>;
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
export function App() {
return <Navigation />;
}ParamListimport { createStaticNavigation } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import type { StaticParamList } from "@react-navigation/native";
const RootStack = createNativeStackNavigator({
initialRouteName: "Home",
screenOptions: { headerShown: true },
screens: {
Home: HomeScreen,
Profile: {
screen: ProfileScreen,
linking: "profile/:userId",
},
},
});
const Navigation = createStaticNavigation(RootStack);
// 声明全局类型——让所有地方的useNavigation()都具备类型安全性
type RootStackParamList = StaticParamList<typeof RootStack>;
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
export function App() {
return <Navigation />;
}ParamListimport { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
};
// Must declare globally for type-safe useNavigation()
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
const Stack = createNativeStackNavigator<RootStackParamList>();
export function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
};
// 必须全局声明以实现类型安全的useNavigation()
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
const Stack = createNativeStackNavigator<RootStackParamList>();
export function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}RootParamListuseNavigation()useRoute()// In any screen component -- no generic needed
function HomeScreen() {
const navigation = useNavigation();
// Type-checked: "Profile" must exist, params must match
navigation.navigate("Profile", { userId: "123" });
// Type error: "Nonexistent" is not in RootParamList
navigation.navigate("Nonexistent"); // compile error
}CompositeScreenPropsNavigatorScreenParamsStaticScreenPropsStaticScreenPropsRootParamListuseNavigation()useRoute()// 在任何屏幕组件中——无需泛型
function HomeScreen() {
const navigation = useNavigation();
// 类型检查:"Profile"必须存在,参数必须匹配
navigation.navigate("Profile", { userId: "123" });
// 类型错误:"Nonexistent"不在RootParamList中
navigation.navigate("Nonexistent"); // 编译错误
}CompositeScreenPropsNavigatorScreenParamsStaticScreenPropsStaticScreenProps// Static API: use the `if` callback on groups
const useIsAuthenticated = () => {
const { isAuthenticated } = useContext(AuthContext);
return isAuthenticated;
};
const useIsGuest = () => !useIsAuthenticated();
const RootStack = createNativeStackNavigator({
screens: {},
groups: {
Auth: {
if: useIsGuest,
screenOptions: { headerShown: false },
screens: { Login: LoginScreen, Register: RegisterScreen },
},
Main: {
if: useIsAuthenticated,
screens: { Home: HomeScreen, Profile: ProfileScreen },
},
},
});if// 静态API:在分组上使用`if`回调
const useIsAuthenticated = () => {
const { isAuthenticated } = useContext(AuthContext);
return isAuthenticated;
};
const useIsGuest = () => !useIsAuthenticated();
const RootStack = createNativeStackNavigator({
screens: {},
groups: {
Auth: {
if: useIsGuest,
screenOptions: { headerShown: false },
screens: { Login: LoginScreen, Register: RegisterScreen },
},
Main: {
if: useIsAuthenticated,
screens: { Home: HomeScreen, Profile: ProfileScreen },
},
},
});iflinkinglinkingNavigationContainer// Static API -- linking defined inline per screen
const RootStack = createNativeStackNavigator({
screens: {
Home: { screen: HomeScreen, linking: "" },
Profile: {
screen: ProfileScreen,
linking: {
path: "user/:userId",
parse: { userId: (id: string) => id.replace(/^@/, "") },
stringify: { userId: (id: string) => `@${id}` },
},
},
},
});
const Navigation = createStaticNavigation(RootStack);
export function App() {
return (
<Navigation
linking={{ prefixes: ["myapp://", "https://myapp.com"] }}
/>
);
}linkingNavigationContainerlinking// 静态API——链接配置内联在每个屏幕中
const RootStack = createNativeStackNavigator({
screens: {
Home: { screen: HomeScreen, linking: "" },
Profile: {
screen: ProfileScreen,
linking: {
path: "user/:userId",
parse: { userId: (id: string) => id.replace(/^@/, "") },
stringify: { userId: (id: string) => `@${id}` },
},
},
},
});
const Navigation = createStaticNavigation(RootStack);
export function App() {
return (
<Navigation
linking={{ prefixes: ["myapp://", "https://myapp.com"] }}
/>
);
}Which stack navigator?
|-- Need custom JS-driven transition animations? --> @react-navigation/stack (JS)
|-- Everything else --> @react-navigation/native-stack (NATIVE)| Feature | Native Stack | JS Stack |
|---|---|---|
| Performance | Native animations, lower memory | JS-driven, higher overhead |
| Transitions | Platform defaults + limited custom | Fully customizable |
| Large titles (iOS) | Supported natively | Not available |
| Search bar (iOS) | headerSearchBarOptions | Must build custom |
| Form sheets | presentation: "formSheet" | Not available |
| Gesture handling | Native, smooth | JS-driven |
选择哪种栈导航器?
|-- 需要自定义JS驱动的转场动画? --> @react-navigation/stack(JS栈)
|-- 其他场景 --> @react-navigation/native-stack(Native栈)| 特性 | Native栈 | JS栈 |
|---|---|---|
| 性能 | 原生动画,更低内存占用 | JS驱动,更高开销 |
| 转场 | 平台默认 + 有限自定义 | 完全可自定义 |
| iOS大标题 | 原生支持 | 不支持 |
| iOS搜索栏 | headerSearchBarOptions | 必须自定义 |
| 表单页 | presentation: "formSheet" | 不支持 |
| 手势处理 | 原生,流畅 | JS驱动 |
useFocusEffectimport { useCallback } from "react";
import { useFocusEffect } from "@react-navigation/native";
function ChatScreen({ roomId }: { roomId: string }) {
useFocusEffect(
useCallback(() => {
const ws = new WebSocket(`wss://chat.example.com/rooms/${roomId}`);
// Cleanup runs when screen loses focus
return () => ws.close();
}, [roomId]),
);
}useCallbackuseFocusEffectimport { useCallback } from "react";
import { useFocusEffect } from "@react-navigation/native";
function ChatScreen({ roomId }: { roomId: string }) {
useFocusEffect(
useCallback(() => {
const ws = new WebSocket(`wss://chat.example.com/rooms/${roomId}`);
// 屏幕失去焦点时执行清理
return () => ws.close();
}, [roomId]),
);
}useCallbackfunction ProductList() {
const navigation = useNavigation();
const handleLongPress = (productId: string) => {
navigation.preload("ProductDetail", { productId });
};
// Later: navigation.navigate("ProductDetail", { productId }) is instant
}function ProductList() {
const navigation = useNavigation();
const handleLongPress = (productId: string) => {
navigation.preload("ProductDetail", { productId });
};
// 后续:navigation.navigate("ProductDetail", { productId })会瞬间完成
}<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{
headerLargeTitleEnabled: true,
headerLargeStyle: { backgroundColor: "#f5f5f5" },
headerSearchBarOptions: {
placeholder: "Search settings...",
onChangeText: (e) => handleSearch(e.nativeEvent.text),
hideWhenScrolling: true,
},
}}
/>headerheaderLeftheaderRight<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{
headerLargeTitleEnabled: true,
headerLargeStyle: { backgroundColor: "#f5f5f5" },
headerSearchBarOptions: {
placeholder: "搜索设置...",
onChangeText: (e) => handleSearch(e.nativeEvent.text),
hideWhenScrolling: true,
},
}}
/>headerheaderLeftheaderRightStarting a new navigation setup?
|-- Can all screens be defined at build time?
| |-- YES --> Static API (simpler TS, auto deep linking)
| +-- NO --> Dynamic API (runtime screen lists)
|
|-- Migrating incrementally from v6?
| +-- YES --> Dynamic API at root, static for new navigators
| (use getComponent() and createPathConfigForStaticNavigation)
|
|-- Need to wrap navigator with providers (e.g. context)?
| +-- Use static API with .with() method开始新的导航设置?
|-- 所有屏幕都能在构建时定义吗?
| |-- 是 --> 静态API(更简洁的TS支持、自动深度链接)
| +-- 否 --> 动态API(运行时屏幕列表)
|
|-- 从v6增量迁移?
| +-- 是 --> 根节点使用动态API,新导航器使用静态API
| (使用getComponent()和createPathConfigForStaticNavigation)
|
|-- 需要用提供者包裹导航器(如context)?
| +-- 使用静态API的.with()方法What navigation pattern?
|-- Linear flow (onboarding, checkout) --> Stack Navigator
|-- Main app sections with persistent bar --> Bottom Tab Navigator
|-- Side menu / settings panel --> Drawer Navigator
|-- Modal overlays --> Stack with presentation: "modal"
|-- Bottom sheets --> Stack with presentation: "formSheet"
|-- Combination --> Nest navigators (tabs inside stack, stacks inside tabs)选择哪种导航模式?
|-- 线性流程(引导页、结账流程) --> 栈导航器
|-- 带持久化栏的主应用板块 --> 底部标签导航器
|-- 侧边菜单/设置面板 --> 抽屉导航器
|-- 模态覆盖层 --> 栈导航器,设置presentation: "modal"
|-- 底部表单 --> 栈导航器,设置presentation: "formSheet"
|-- 组合模式 --> 嵌套导航器(栈内嵌套标签,标签内嵌套栈)How to move between screens?
|-- Push new screen forward --> navigation.navigate("Screen", params)
|-- Go back to specific screen --> navigation.popTo("Screen", params)
|-- Go back one screen --> navigation.goBack()
|-- Replace current screen --> navigation.replace("Screen", params)
|-- Reset entire stack --> navigation.reset({ routes: [...] })
|-- Navigate to nested screen --> navigation.navigate("Parent", { screen: "Child" })如何在屏幕间跳转?
|-- 向前推入新屏幕 --> navigation.navigate("Screen", params)
|-- 返回指定屏幕 --> navigation.popTo("Screen", params)
|-- 返回上一屏幕 --> navigation.goBack()
|-- 替换当前屏幕 --> navigation.replace("Screen", params)
|-- 重置整个栈 --> navigation.reset({ routes: [...] })
|-- 导航到嵌套屏幕 --> navigation.navigate("Parent", { screen: "Child" })navigate()navigate()popTo()navigation.navigate("NestedScreen")navigate("ParentScreen", { screen: "NestedScreen" })@react-navigation/stackRootParamListuseNavigation()header<Stack.Screen component={() => <MyScreen />} />useFocusEffectuseEffectfontsuseFocusEffectuseCallbackusePreventRemovenavigation.setOptions()options{ route, navigation }headerSearchBarOptionscontentInsetAdjustmentBehavior="automatic"headerBackButtonDisplayModeheaderBackTitleVisibleunmountOnBlurpopToTopOnBlur: trueuseIsFocusedRNScreensFragmentFactoryMainActivityLink<Link screen="Profile" params={{ userId }}><Link to="/profile/123">navigate()navigate()popTo()navigation.navigate("NestedScreen")navigate("ParentScreen", { screen: "NestedScreen" })@react-navigation/stackRootParamListuseNavigation()header<Stack.Screen component={() => <MyScreen />} />useFocusEffectuseEffectfontsuseFocusEffectuseCallbackusePreventRemovenavigation.setOptions()options{ route, navigation }headerSearchBarOptionscontentInsetAdjustmentBehavior="automatic"headerBackButtonDisplayModeheaderBackTitleVisibleunmountOnBlurpopToTopOnBlur: trueuseIsFocusedMainActivityRNScreensFragmentFactoryLink<Link screen="Profile" params={{ userId }}><Link to="/profile/123">All code must follow project conventions in CLAUDE.md
ReactNavigation.RootParamListuseNavigationcreateNativeStackNavigator@react-navigation/stackpopTo()navigate()useFocusEffectuseCallbacknavigation.navigate('NestedScreen')所有代码必须遵循CLAUDE.md中的项目约定
ReactNavigation.RootParamListuseNavigationcreateNativeStackNavigator@react-navigation/stackpopTo()navigate()useFocusEffectuseCallbacknavigation.navigate('NestedScreen')