Best practices and rules for coding in React Native Expo projects, specifically using Expo Router.
Follow these rules and best practices when working on React Native projects with Expo and Expo Router.
app/ directory. Files in app/ become routes.
index.tsx -> /settings.tsx -> /settings(tabs)/_layout.tsx -> Layout for a tab group.[id].tsx -> Dynamic route (e.g., /user/123)._layout.tsx to define navigation structure (Stack, Tabs, Drawer) and wrap screens.
export default function Layout() { return <Stack />; }<Link href="/path" asChild> from expo-router for navigation.android and ios folders. They are recreated every time a build is created.View, Text, Image, TouchableOpacity from react-native. Do not use HTML tags (div, p, img).src/components/ directory and import it.className props.StyleSheet.create. Avoid inline styles for performance.useWindowDimensions for responsive logic if needed, but prefer flexible layouts (Flexbox).SafeAreaView from react-native-safe-area-context to handle notches and navigation bars properly.Platform.OS or .ios.tsx / .android.tsx extensions for platform-specific variations.react-native-gesture-handler for advanced gestures.react-native-pager-view package for gesture-based swiping.expo-image for optimized image loading.refreshControl prop on ScrollView.useState, useEffect, useCallback).useEffect or event handlers.src/hooks/useAuth.ts).createContext) to manage it. Always create a custom hook (e.g., useMyContext) to consume the context easily. Avoid excessive prop drilling.
useEffect with dependenciesuseEffect without dependenciesreturn (UI JSX)FlatList or SectionList for long lists. Never map inside a ScrollView.React.memo, useMemo, and useCallback to prevent unnecessary re-renders.npx expo install package-name to ensure version compatibility.useCameraPermissions).useFonts.src/services/api/ directory.src/services/api/profile.ts).fetch or axios directly in UI components; import functions from the services.null or empty in UI components. Show loading states or empty placeholders; never assume data exists.app/): kebab-case (e.g., src/app/handover-to-rider.tsx).PascalCase (e.g., src/components/UserProfile.tsx).camelCase, prefixed with use (e.g., src/hooks/useAuth.ts).camelCase (e.g., src/services/apiService.ts, src/utils/dateUtils.ts).PascalCase (e.g., function UserProfile() {}).camelCase (e.g., updatedUser, fetchData()).UPPER_SNAKE_CASE for global constants (e.g., API_URL).PascalCase (e.g., UserData, AuthResponse). Prefer type for object shapes, unions, and generics; use interface only when needed (e.g., declaration merging or extending library types).JSON.stringify(object, null, 2) to print them in a readable, formatted way.src/utils/ folder (e.g., src/utils/dateUtils.ts, src/utils/stringUtils.ts), and import it where needed.window or document objects (unless inside a web-only check).console.log in production code.