[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6ENZHWVHRGGCCXD8NMBNRT0":3,"skill-same:01M6ENZHWVHRGGCCXD8NMBNRT0":72},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":46,"repositoryHtmlUrl":47,"repositoryHomepageUrl":48,"ownerHtmlUrl":49,"ownerBlogUrl":6,"ownerDescription":50,"updatedAt":51,"install":52,"resources":65},"01M6ENZHWVHRGGCCXD8NMBNRT0","rn-navigation",null,"Expo Router navigation patterns for React Native. Use when implementing navigation, routing, deep links, tab bars, modals, or handling navigation state in Expo apps.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-navigation\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37],"navigation","rn navigation","react","routing","state","react native","use","router","expo","patterns","deep","apps","native","expo router","2026-11-10 10:12:30",false,"---\nname: rn-navigation\ndescription: Expo Router navigation patterns for React Native. Use when implementing navigation, routing, deep links, tab bars, modals, or handling navigation state in Expo apps.\n---\n\n# React Native Navigation (Expo Router)\n\n## File-Based Routing Fundamentals\n\nExpo Router uses file-system based routing. Files in `app\u002F` become routes.\n\n### Route Structure\n\n```\napp\u002F\n├── _layout.tsx          # Root layout (providers, global UI)\n├── index.tsx            # \"\u002F\" route\n├── (tabs)\u002F              # Tab group (parentheses = layout group)\n│   ├── _layout.tsx      # Tab bar configuration\n│   ├── home.tsx         # \"\u002Fhome\" tab\n│   └── profile.tsx      # \"\u002Fprofile\" tab\n├── (auth)\u002F              # Auth flow group\n│   ├── _layout.tsx      # Auth-specific layout\n│   ├── login.tsx        # \"\u002Flogin\"\n│   └── register.tsx     # \"\u002Fregister\"\n├── settings\u002F\n│   ├── index.tsx        # \"\u002Fsettings\"\n│   └── [id].tsx         # \"\u002Fsettings\u002F123\" (dynamic)\n└── [...missing].tsx     # Catch-all 404\n```\n\n### Layout Groups `(groupName)`\n\nParentheses create layout groups - they affect layout hierarchy but not URL:\n\n```typescript\n\u002F\u002F app\u002F(tabs)\u002F_layout.tsx\nimport { Tabs } from 'expo-router';\n\nexport default function TabLayout() {\n  return (\n    \u003CTabs>\n      \u003CTabs.Screen \n        name=\"home\" \n        options={{ \n          title: 'Home',\n          tabBarIcon: ({ color }) => \u003CHomeIcon color={color} \u002F>,\n        }} \n      \u002F>\n      \u003CTabs.Screen \n        name=\"profile\" \n        options={{ title: 'Profile' }} \n      \u002F>\n    \u003C\u002FTabs>\n  );\n}\n```\n\n### Dynamic Routes `[param]`\n\n```typescript\n\u002F\u002F app\u002Fplayer\u002F[id].tsx\nimport { useLocalSearchParams } from 'expo-router';\n\nexport default function PlayerScreen() {\n  const { id } = useLocalSearchParams\u003C{ id: string }>();\n  \n  return \u003CPlayerProfile playerId={id} \u002F>;\n}\n```\n\n### Catch-All Routes `[...slug]`\n\n```typescript\n\u002F\u002F app\u002F[...missing].tsx\nimport { Link, Stack } from 'expo-router';\n\nexport default function NotFound() {\n  return (\n    \u003C>\n      \u003CStack.Screen options={{ title: 'Not Found' }} \u002F>\n      \u003CLink href=\"\u002F\">Go home\u003C\u002FLink>\n    \u003C\u002F>\n  );\n}\n```\n\n## Navigation Patterns\n\n### Programmatic Navigation\n\n```typescript\nimport { useRouter, Link } from 'expo-router';\n\nfunction MyComponent() {\n  const router = useRouter();\n  \n  \u002F\u002F Navigate with push (adds to stack)\n  router.push('\u002Fplayer\u002F123');\n  \n  \u002F\u002F Navigate with params\n  router.push({\n    pathname: '\u002Fplayer\u002F[id]',\n    params: { id: '123' },\n  });\n  \n  \u002F\u002F Replace current screen (no back)\n  router.replace('\u002Fhome');\n  \n  \u002F\u002F Go back\n  router.back();\n  \n  \u002F\u002F Navigate to root\n  router.navigate('\u002F');\n  \n  \u002F\u002F Dismiss modal\n  router.dismiss();\n}\n```\n\n### Link Component\n\n```tsx\nimport { Link } from 'expo-router';\n\n\u002F\u002F Simple link\n\u003CLink href=\"\u002Fsettings\">Settings\u003C\u002FLink>\n\n\u002F\u002F With params\n\u003CLink href={{ pathname: '\u002Fplayer\u002F[id]', params: { id: '123' } }}>\n  View Player\n\u003C\u002FLink>\n\n\u002F\u002F As button\n\u003CLink href=\"\u002Fschedule\" asChild>\n  \u003CPressable>\n    \u003CText>View Schedule\u003C\u002FText>\n  \u003C\u002FPressable>\n\u003C\u002FLink>\n\n\u002F\u002F Replace instead of push\n\u003CLink href=\"\u002Fhome\" replace>Home\u003C\u002FLink>\n```\n\n## Stack Navigation\n\n```typescript\n\u002F\u002F app\u002F_layout.tsx\nimport { Stack } from 'expo-router';\n\nexport default function RootLayout() {\n  return (\n    \u003CStack>\n      \u003CStack.Screen name=\"(tabs)\" options={{ headerShown: false }} \u002F>\n      \u003CStack.Screen \n        name=\"modal\" \n        options={{ presentation: 'modal' }} \n      \u002F>\n      \u003CStack.Screen \n        name=\"player\u002F[id]\" \n        options={{ \n          headerTitle: 'Player',\n          headerBackTitle: 'Back',\n        }} \n      \u002F>\n    \u003C\u002FStack>\n  );\n}\n```\n\n### Dynamic Header Options\n\n```typescript\n\u002F\u002F app\u002Fplayer\u002F[id].tsx\nimport { Stack, useLocalSearchParams } from 'expo-router';\n\nexport default function PlayerScreen() {\n  const { id } = useLocalSearchParams();\n  const player = usePlayer(id);\n  \n  return (\n    \u003C>\n      \u003CStack.Screen \n        options={{ \n          headerTitle: player?.name ?? 'Loading...',\n          headerRight: () => (\n            \u003CEditButton playerId={id} \u002F>\n          ),\n        }} \n      \u002F>\n      \u003CPlayerProfile player={player} \u002F>\n    \u003C\u002F>\n  );\n}\n```\n\n## Modals\n\n```typescript\n\u002F\u002F Present as modal from anywhere\nrouter.push('\u002Fbooking-modal');\n\n\u002F\u002F app\u002Fbooking-modal.tsx\nimport { Stack, useRouter } from 'expo-router';\n\nexport default function BookingModal() {\n  const router = useRouter();\n  \n  const handleComplete = () => {\n    router.dismiss(); \u002F\u002F or router.back()\n  };\n  \n  return (\n    \u003C>\n      \u003CStack.Screen \n        options={{ \n          presentation: 'modal',\n          headerLeft: () => (\n            \u003CButton title=\"Cancel\" onPress={() => router.dismiss()} \u002F>\n          ),\n        }} \n      \u002F>\n      \u003CBookingForm onComplete={handleComplete} \u002F>\n    \u003C\u002F>\n  );\n}\n\n\u002F\u002F In _layout.tsx, configure the modal screen\n\u003CStack.Screen \n  name=\"booking-modal\" \n  options={{ \n    presentation: 'modal',\n    headerShown: true,\n  }} \n\u002F>\n```\n\n## Deep Linking\n\n### Configure scheme in app.json\n\n```json\n{\n  \"expo\": {\n    \"scheme\": \"myapp\",\n    \"ios\": {\n      \"bundleIdentifier\": \"com.yourcompany.myapp\",\n      \"associatedDomains\": [\"applinks:yourdomain.com\"]\n    }\n  }\n}\n```\n\n### Test deep links\n\n```bash\n# iOS Simulator\nnpx uri-scheme open \"myapp:\u002F\u002Fplayer\u002F123\" --ios\n\n# Physical device\nnpx expo start --dev-client\n# Then open myapp:\u002F\u002Fplayer\u002F123 in Safari\n```\n\n### Universal Links (iOS)\n\n1. Add `associatedDomains` to app.json\n2. Host `apple-app-site-association` file at `https:\u002F\u002Fyourdomain.com\u002F.well-known\u002Fapple-app-site-association`:\n\n```json\n{\n  \"applinks\": {\n    \"apps\": [],\n    \"details\": [{\n      \"appID\": \"TEAMID.com.yourcompany.myapp\",\n      \"paths\": [\"\u002Fplayer\u002F*\", \"\u002Fschedule\u002F*\"]\n    }]\n  }\n}\n```\n\n### Handle incoming links\n\n```typescript\n\u002F\u002F app\u002F_layout.tsx\nimport { useEffect } from 'react';\nimport * as Linking from 'expo-linking';\nimport { useRouter } from 'expo-router';\n\nexport default function RootLayout() {\n  const router = useRouter();\n  \n  useEffect(() => {\n    \u002F\u002F Handle link that opened the app\n    Linking.getInitialURL().then((url) => {\n      if (url) handleDeepLink(url);\n    });\n    \n    \u002F\u002F Handle links while app is open\n    const subscription = Linking.addEventListener('url', ({ url }) => {\n      handleDeepLink(url);\n    });\n    \n    return () => subscription.remove();\n  }, []);\n  \n  function handleDeepLink(url: string) {\n    const { path, queryParams } = Linking.parse(url);\n    \u002F\u002F Expo Router handles most cases automatically\n    \u002F\u002F Custom logic here for special cases\n  }\n  \n  return \u003CStack \u002F>;\n}\n```\n\n## Common Patterns\n\n### Auth-Protected Routes\n\nSee `rn-auth` skill for full auth context pattern. Key navigation piece:\n\n```typescript\n\u002F\u002F app\u002F_layout.tsx\nexport default function RootLayout() {\n  const { token, isLoading } = useAuth();\n  const segments = useSegments();\n  const router = useRouter();\n\n  useEffect(() => {\n    if (isLoading) return;\n    \n    const inAuthGroup = segments[0] === '(auth)';\n    \n    if (!token && !inAuthGroup) {\n      router.replace('\u002F(auth)\u002Flogin');\n    } else if (token && inAuthGroup) {\n      router.replace('\u002F(tabs)\u002Fhome');\n    }\n  }, [token, isLoading]);\n\n  return (\n    \u003CStack>\n      \u003CStack.Screen name=\"(auth)\" options={{ headerShown: false }} \u002F>\n      \u003CStack.Screen name=\"(tabs)\" options={{ headerShown: false }} \u002F>\n    \u003C\u002FStack>\n  );\n}\n```\n\n### Preventing Back Navigation\n\n```typescript\n\u002F\u002F After login success, replace to prevent back to login\nrouter.replace('\u002F(tabs)\u002Fhome');\n\n\u002F\u002F For onboarding completion\nrouter.replace('\u002Fhome');\n\n\u002F\u002F In screen options\n\u003CStack.Screen \n  name=\"checkout-complete\" \n  options={{ \n    headerBackVisible: false,\n    gestureEnabled: false, \u002F\u002F Prevent swipe back\n  }} \n\u002F>\n```\n\n### Passing Data Between Screens\n\n```typescript\n\u002F\u002F Option 1: URL params (simple data, survives refresh)\nrouter.push({\n  pathname: '\u002Fconfirm',\n  params: { date: '2025-01-15', courtId: '5' },\n});\n\n\u002F\u002F Reading\nconst { date, courtId } = useLocalSearchParams();\n\n\u002F\u002F Option 2: Global state for complex data (doesn't survive refresh)\n\u002F\u002F Use context, zustand, or similar\n```\n\n## Debugging Navigation\n\n### Log current route\n\n```typescript\nimport { usePathname, useSegments } from 'expo-router';\n\nfunction DebugNav() {\n  const pathname = usePathname();\n  const segments = useSegments();\n  \n  console.log('Current path:', pathname);\n  console.log('Segments:', segments);\n  \n  return null;\n}\n```\n\n### Common issues\n\n| Issue | Solution |\n|-------|----------|\n| Screen not found | Check file name matches route, check `_layout.tsx` includes screen |\n| Tabs not showing | Ensure tab screens are direct children of tab `_layout.tsx` |\n| Back button missing | Check `headerShown` in parent and child layouts |\n| Deep link not working | Verify scheme in app.json, test with `uri-scheme` CLI |\n| Params undefined | Use `useLocalSearchParams` not `useSearchParams` |\n","# React Native Navigation (Expo Router)\n\n## File-Based Routing Fundamentals\n\nExpo Router uses file-system based routing. Files in `app\u002F` become routes.\n\n### Route Structure\n\n```\napp\u002F\n├── _layout.tsx          # Root layout (providers, global UI)\n├── index.tsx            # \"\u002F\" route\n├── (tabs)\u002F              # Tab group (parentheses = layout group)\n│   ├── _layout.tsx      # Tab bar configuration\n│   ├── home.tsx         # \"\u002Fhome\" tab\n│   └── profile.tsx      # \"\u002Fprofile\" tab\n├── (auth)\u002F              # Auth flow group\n│   ├── _layout.tsx      # Auth-specific layout\n│   ├── login.tsx        # \"\u002Flogin\"\n│   └── register.tsx     # \"\u002Fregister\"\n├── settings\u002F\n│   ├── index.tsx        # \"\u002Fsettings\"\n│   └── [id].tsx         # \"\u002Fsettings\u002F123\" (dynamic)\n└── [...missing].tsx     # Catch-all 404\n```\n\n### Layout Groups `(groupName)`\n\nParentheses create layout groups - they affect layout hierarchy but not URL:\n\n```typescript\n\u002F\u002F app\u002F(tabs)\u002F_layout.tsx\nimport { Tabs } from 'expo-router';\n\nexport default function TabLayout() {\n  return (\n    \u003CTabs>\n      \u003CTabs.Screen \n        name=\"home\" \n        options={{ \n          title: 'Home',\n          tabBarIcon: ({ color }) => \u003CHomeIcon color={color} \u002F>,\n        }} \n      \u002F>\n      \u003CTabs.Screen \n        name=\"profile\" \n        options={{ title: 'Profile' }} \n      \u002F>\n    \u003C\u002FTabs>\n  );\n}\n```\n\n### Dynamic Routes `[param]`\n\n```typescript\n\u002F\u002F app\u002Fplayer\u002F[id].tsx\nimport { useLocalSearchParams } from 'expo-router';\n\nexport default function PlayerScreen() {\n  const { id } = useLocalSearchParams\u003C{ id: string }>();\n  \n  return \u003CPlayerProfile playerId={id} \u002F>;\n}\n```\n\n### Catch-All Routes `[...slug]`\n\n```typescript\n\u002F\u002F app\u002F[...missing].tsx\nimport { Link, Stack } from 'expo-router';\n\nexport default function NotFound() {\n  return (\n    \u003C>\n      \u003CStack.Screen options={{ title: 'Not Found' }} \u002F>\n      \u003CLink href=\"\u002F\">Go home\u003C\u002FLink>\n    \u003C\u002F>\n  );\n}\n```\n\n## Navigation Patterns\n\n### Programmatic Navigation\n\n```typescript\nimport { useRouter, Link } from 'expo-router';\n\nfunction MyComponent() {\n  const router = useRouter();\n  \n  \u002F\u002F Navigate with push (adds to stack)\n  router.push('\u002Fplayer\u002F123');\n  \n  \u002F\u002F Navigate with params\n  router.push({\n    pathname: '\u002Fplayer\u002F[id]',\n    params: { id: '123' },\n  });\n  \n  \u002F\u002F Replace current screen (no back)\n  router.replace('\u002Fhome');\n  \n  \u002F\u002F Go back\n  router.back();\n  \n  \u002F\u002F Navigate to root\n  router.navigate('\u002F');\n  \n  \u002F\u002F Dismiss modal\n  router.dismiss();\n}\n```\n\n### Link Component\n\n```tsx\nimport { Link } from 'expo-router';\n\n\u002F\u002F Simple link\n\u003CLink href=\"\u002Fsettings\">Settings\u003C\u002FLink>\n\n\u002F\u002F With params\n\u003CLink href={{ pathname: '\u002Fplayer\u002F[id]', params: { id: '123' } }}>\n  View Player\n\u003C\u002FLink>\n\n\u002F\u002F As button\n\u003CLink href=\"\u002Fschedule\" asChild>\n  \u003CPressable>\n    \u003CText>View Schedule\u003C\u002FText>\n  \u003C\u002FPressable>\n\u003C\u002FLink>\n\n\u002F\u002F Replace instead of push\n\u003CLink href=\"\u002Fhome\" replace>Home\u003C\u002FLink>\n```\n\n## Stack Navigation\n\n```typescript\n\u002F\u002F app\u002F_layout.tsx\nimport { Stack } from 'expo-router';\n\nexport default function RootLayout() {\n  return (\n    \u003CStack>\n      \u003CStack.Screen name=\"(tabs)\" options={{ headerShown: false }} \u002F>\n      \u003CStack.Screen \n        name=\"modal\" \n        options={{ presentation: 'modal' }} \n      \u002F>\n      \u003CStack.Screen \n        name=\"player\u002F[id]\" \n        options={{ \n          headerTitle: 'Player',\n          headerBackTitle: 'Back',\n        }} \n      \u002F>\n    \u003C\u002FStack>\n  );\n}\n```\n\n### Dynamic Header Options\n\n```typescript\n\u002F\u002F app\u002Fplayer\u002F[id].tsx\nimport { Stack, useLocalSearchParams } from 'expo-router';\n\nexport default function PlayerScreen() {\n  const { id } = useLocalSearchParams();\n  const player = usePlayer(id);\n  \n  return (\n    \u003C>\n      \u003CStack.Screen \n        options={{ \n          headerTitle: player?.name ?? 'Loading...',\n          headerRight: () => (\n            \u003CEditButton playerId={id} \u002F>\n          ),\n        }} \n      \u002F>\n      \u003CPlayerProfile player={player} \u002F>\n    \u003C\u002F>\n  );\n}\n```\n\n## Modals\n\n```typescript\n\u002F\u002F Present as modal from anywhere\nrouter.push('\u002Fbooking-modal');\n\n\u002F\u002F app\u002Fbooking-modal.tsx\nimport { Stack, useRouter } from 'expo-router';\n\nexport default function BookingModal() {\n  const router = useRouter();\n  \n  const handleComplete = () => {\n    router.dismiss(); \u002F\u002F or router.back()\n  };\n  \n  return (\n    \u003C>\n      \u003CStack.Screen \n        options={{ \n          presentation: 'modal',\n          headerLeft: () => (\n            \u003CButton title=\"Cancel\" onPress={() => router.dismiss()} \u002F>\n          ),\n        }} \n      \u002F>\n      \u003CBookingForm onComplete={handleComplete} \u002F>\n    \u003C\u002F>\n  );\n}\n\n\u002F\u002F In _layout.tsx, configure the modal screen\n\u003CStack.Screen \n  name=\"booking-modal\" \n  options={{ \n    presentation: 'modal',\n    headerShown: true,\n  }} \n\u002F>\n```\n\n## Deep Linking\n\n### Configure scheme in app.json\n\n```json\n{\n  \"expo\": {\n    \"scheme\": \"myapp\",\n    \"ios\": {\n      \"bundleIdentifier\": \"com.yourcompany.myapp\",\n      \"associatedDomains\": [\"applinks:yourdomain.com\"]\n    }\n  }\n}\n```\n\n### Test deep links\n\n```bash\n# iOS Simulator\nnpx uri-scheme open \"myapp:\u002F\u002Fplayer\u002F123\" --ios\n\n# Physical device\nnpx expo start --dev-client\n# Then open myapp:\u002F\u002Fplayer\u002F123 in Safari\n```\n\n### Universal Links (iOS)\n\n1. Add `associatedDomains` to app.json\n2. Host `apple-app-site-association` file at `https:\u002F\u002Fyourdomain.com\u002F.well-known\u002Fapple-app-site-association`:\n\n```json\n{\n  \"applinks\": {\n    \"apps\": [],\n    \"details\": [{\n      \"appID\": \"TEAMID.com.yourcompany.myapp\",\n      \"paths\": [\"\u002Fplayer\u002F*\", \"\u002Fschedule\u002F*\"]\n    }]\n  }\n}\n```\n\n### Handle incoming links\n\n```typescript\n\u002F\u002F app\u002F_layout.tsx\nimport { useEffect } from 'react';\nimport * as Linking from 'expo-linking';\nimport { useRouter } from 'expo-router';\n\nexport default function RootLayout() {\n  const router = useRouter();\n  \n  useEffect(() => {\n    \u002F\u002F Handle link that opened the app\n    Linking.getInitialURL().then((url) => {\n      if (url) handleDeepLink(url);\n    });\n    \n    \u002F\u002F Handle links while app is open\n    const subscription = Linking.addEventListener('url', ({ url }) => {\n      handleDeepLink(url);\n    });\n    \n    return () => subscription.remove();\n  }, []);\n  \n  function handleDeepLink(url: string) {\n    const { path, queryParams } = Linking.parse(url);\n    \u002F\u002F Expo Router handles most cases automatically\n    \u002F\u002F Custom logic here for special cases\n  }\n  \n  return \u003CStack \u002F>;\n}\n```\n\n## Common Patterns\n\n### Auth-Protected Routes\n\nSee `rn-auth` skill for full auth context pattern. Key navigation piece:\n\n```typescript\n\u002F\u002F app\u002F_layout.tsx\nexport default function RootLayout() {\n  const { token, isLoading } = useAuth();\n  const segments = useSegments();\n  const router = useRouter();\n\n  useEffect(() => {\n    if (isLoading) return;\n    \n    const inAuthGroup = segments[0] === '(auth)';\n    \n    if (!token && !inAuthGroup) {\n      router.replace('\u002F(auth)\u002Flogin');\n    } else if (token && inAuthGroup) {\n      router.replace('\u002F(tabs)\u002Fhome');\n    }\n  }, [token, isLoading]);\n\n  return (\n    \u003CStack>\n      \u003CStack.Screen name=\"(auth)\" options={{ headerShown: false }} \u002F>\n      \u003CStack.Screen name=\"(tabs)\" options={{ headerShown: false }} \u002F>\n    \u003C\u002FStack>\n  );\n}\n```\n\n### Preventing Back Navigation\n\n```typescript\n\u002F\u002F After login success, replace to prevent back to login\nrouter.replace('\u002F(tabs)\u002Fhome');\n\n\u002F\u002F For onboarding completion\nrouter.replace('\u002Fhome');\n\n\u002F\u002F In screen options\n\u003CStack.Screen \n  name=\"checkout-complete\" \n  options={{ \n    headerBackVisible: false,\n    gestureEnabled: false, \u002F\u002F Prevent swipe back\n  }} \n\u002F>\n```\n\n### Passing Data Between Screens\n\n```typescript\n\u002F\u002F Option 1: URL params (simple data, survives refresh)\nrouter.push({\n  pathname: '\u002Fconfirm',\n  params: { date: '2025-01-15', courtId: '5' },\n});\n\n\u002F\u002F Reading\nconst { date, courtId } = useLocalSearchParams();\n\n\u002F\u002F Option 2: Global state for complex data (doesn't survive refresh)\n\u002F\u002F Use context, zustand, or similar\n```\n\n## Debugging Navigation\n\n### Log current route\n\n```typescript\nimport { usePathname, useSegments } from 'expo-router';\n\nfunction DebugNav() {\n  const pathname = usePathname();\n  const segments = useSegments();\n  \n  console.log('Current path:', pathname);\n  console.log('Segments:', segments);\n  \n  return null;\n}\n```\n\n### Common issues\n\n| Issue | Solution |\n|-------|----------|\n| Screen not found | Check file name matches route, check `_layout.tsx` includes screen |\n| Tabs not showing | Ensure tab screens are direct children of tab `_layout.tsx` |\n| Back button missing | Check `headerShown` in parent and child layouts |\n| Deep link not working | Verify scheme in app.json, test with `uri-scheme` CLI |\n| Params undefined | Use `useLocalSearchParams` not `useSearchParams` |\n",{"name":5,"description":7},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-navigation",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill rn-navigation",{"tool":58,"command":59},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill rn-navigation",{"tool":61,"command":62},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill rn-navigation","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-navigation\u002FSKILL.md",true,[66],{"path":67,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":70,"sourceHtmlUrl":71},"skill-report.json","REFERENCE","参考文档",9608,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fcjharmath\u002Frn-navigation\u002Fskill-report.json",[73,85,95,103,109,116],{"skillNo":74,"name":75,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":81,"publishedAt":38},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[78],{"categoryNo":79,"categoryName":80,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[82,83,84],"model","model hierarchy","model hierarchy skill",{"skillNo":86,"name":87,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":91,"publishedAt":38},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[90],{"categoryNo":79,"categoryName":80,"taxonomyType":21,"taxonomyTypeDesc":22},[92,93,94],"MCP","zoom","zoom mcp",{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":38},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[101,102,35,93],"sdk","zoom apps sdk",{"skillNo":104,"name":105,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":108,"publishedAt":38},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[105],{"skillNo":110,"name":111,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":115,"publishedAt":38},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[114],{"categoryNo":79,"categoryName":80,"taxonomyType":21,"taxonomyTypeDesc":22},[111],{"skillNo":117,"name":118,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":38},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[118]]