react-native-sop-docs/05-state-management-navigation/navigation.md

364 lines
9.5 KiB
Markdown

# Navigation Setup
## Installation
```bash
yarn add @react-navigation/native @react-navigation/stack @react-navigation/bottom-tabs
yarn add react-native-screens react-native-safe-area-context react-native-gesture-handler
```
## iOS Setup
```bash
cd ios && pod install
```
## Navigation Types
```typescript
// src/navigation/types.ts
export type RootStackParamList = {
Auth: undefined;
Main: undefined;
Splash: undefined;
};
export type AuthStackParamList = {
Login: undefined;
Register: undefined;
ForgotPassword: undefined;
OTPVerification: {email: string};
};
export type MainTabParamList = {
Home: undefined;
Profile: undefined;
Settings: undefined;
Notifications: undefined;
};
export type HomeStackParamList = {
HomeScreen: undefined;
Details: {id: string};
Search: undefined;
};
```
## Root Navigator
```typescript
// src/navigation/RootNavigator.tsx
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {useAppSelector} from '@redux/hooks';
import {selectIsAuthenticated} from '@redux/selectors/authSelectors';
import AuthNavigator from './AuthNavigator';
import MainNavigator from './MainNavigator';
import SplashScreen from '@screens/SplashScreen';
import {RootStackParamList} from './types';
const Stack = createStackNavigator<RootStackParamList>();
export const RootNavigator: React.FC = () => {
const isAuthenticated = useAppSelector(selectIsAuthenticated);
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
// Simulate app initialization
const timer = setTimeout(() => {
setIsLoading(false);
}, 2000);
return () => clearTimeout(timer);
}, []);
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}}>
{isLoading ? (
<Stack.Screen name="Splash" component={SplashScreen} />
) : isAuthenticated ? (
<Stack.Screen name="Main" component={MainNavigator} />
) : (
<Stack.Screen name="Auth" component={AuthNavigator} />
)}
</Stack.Navigator>
</NavigationContainer>
);
};
```
## Auth Navigator
```typescript
// src/navigation/AuthNavigator.tsx
import React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {AuthStackParamList} from './types';
import LoginScreen from '@screens/Auth/LoginScreen';
import RegisterScreen from '@screens/Auth/RegisterScreen';
import ForgotPasswordScreen from '@screens/Auth/ForgotPasswordScreen';
import OTPVerificationScreen from '@screens/Auth/OTPVerificationScreen';
const Stack = createStackNavigator<AuthStackParamList>();
const AuthNavigator: React.FC = () => {
return (
<Stack.Navigator
initialRouteName="Login"
screenOptions={{
headerShown: false,
cardStyleInterpolator: ({current, layouts}) => {
return {
cardStyle: {
transform: [
{
translateX: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.width, 0],
}),
},
],
},
};
},
}}>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="ForgotPassword" component={ForgotPasswordScreen} />
<Stack.Screen name="OTPVerification" component={OTPVerificationScreen} />
</Stack.Navigator>
);
};
export default AuthNavigator;
```
## Main Navigator (Bottom Tabs)
```typescript
// src/navigation/MainNavigator.tsx
import React from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {MainTabParamList} from './types';
import {CustomIcon} from '@components/common/CustomIcon';
import {useTheme} from '@providers/ThemeProvider';
import HomeNavigator from './HomeNavigator';
import ProfileScreen from '@screens/Profile/ProfileScreen';
import SettingsScreen from '@screens/Settings/SettingsScreen';
import NotificationsScreen from '@screens/Notifications/NotificationsScreen';
const Tab = createBottomTabNavigator<MainTabParamList>();
const MainNavigator: React.FC = () => {
const {colors} = useTheme();
return (
<Tab.Navigator
screenOptions={({route}) => ({
headerShown: false,
tabBarIcon: ({focused, color, size}) => {
let iconName: string;
switch (route.name) {
case 'Home':
iconName = 'home';
break;
case 'Profile':
iconName = 'user';
break;
case 'Settings':
iconName = 'settings';
break;
case 'Notifications':
iconName = 'bell';
break;
default:
iconName = 'home';
}
return <CustomIcon name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: colors.primary[500],
tabBarInactiveTintColor: colors.neutral.gray500,
tabBarStyle: {
backgroundColor: colors.neutral.white,
borderTopColor: colors.neutral.gray200,
paddingBottom: 5,
height: 60,
},
tabBarLabelStyle: {
fontSize: 12,
fontWeight: '500',
},
})}>
<Tab.Screen name="Home" component={HomeNavigator} />
<Tab.Screen name="Profile" component={ProfileScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
<Tab.Screen name="Notifications" component={NotificationsScreen} />
</Tab.Navigator>
);
};
export default MainNavigator;
```
## Home Stack Navigator
```typescript
// src/navigation/HomeNavigator.tsx
import React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {HomeStackParamList} from './types';
import HomeScreen from '@screens/Home/HomeScreen';
import DetailsScreen from '@screens/Home/DetailsScreen';
import SearchScreen from '@screens/Home/SearchScreen';
const Stack = createStackNavigator<HomeStackParamList>();
const HomeNavigator: React.FC = () => {
return (
<Stack.Navigator
initialRouteName="HomeScreen"
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="Search" component={SearchScreen} />
</Stack.Navigator>
);
};
export default HomeNavigator;
```
## Navigation Service
```typescript
// src/navigation/NavigationService.ts
import {createNavigationContainerRef, StackActions} from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef();
export function navigate(name: string, params?: any) {
if (navigationRef.isReady()) {
navigationRef.navigate(name as never, params as never);
}
}
export function goBack() {
if (navigationRef.isReady()) {
navigationRef.goBack();
}
}
export function reset(routeName: string) {
if (navigationRef.isReady()) {
navigationRef.reset({
index: 0,
routes: [{name: routeName}],
});
}
}
export function push(name: string, params?: any) {
if (navigationRef.isReady()) {
navigationRef.dispatch(StackActions.push(name, params));
}
}
export function replace(name: string, params?: any) {
if (navigationRef.isReady()) {
navigationRef.dispatch(StackActions.replace(name, params));
}
}
```
## Navigation Hooks
```typescript
// src/hooks/useNavigation.ts
import {useNavigation as useRNNavigation} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import {RootStackParamList} from '@navigation/types';
export type NavigationProp = StackNavigationProp<RootStackParamList>;
export const useNavigation = () => {
return useRNNavigation<NavigationProp>();
};
```
## Deep Linking
```typescript
// src/navigation/LinkingConfiguration.ts
import {LinkingOptions} from '@react-navigation/native';
import {RootStackParamList} from './types';
const linking: LinkingOptions<RootStackParamList> = {
prefixes: ['saayam://'],
config: {
screens: {
Auth: {
screens: {
Login: 'login',
Register: 'register',
ForgotPassword: 'forgot-password',
OTPVerification: 'otp-verification',
},
},
Main: {
screens: {
Home: {
screens: {
HomeScreen: 'home',
Details: 'details/:id',
Search: 'search',
},
},
Profile: 'profile',
Settings: 'settings',
Notifications: 'notifications',
},
},
},
},
};
export default linking;
```
## Navigation Container Setup
```typescript
// App.tsx (updated)
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {Provider} from 'react-redux';
import {PersistGate} from 'redux-persist/integration/react';
import {store, persistor} from './src/redux/store';
import {RootNavigator} from './src/navigation/RootNavigator';
import {navigationRef} from './src/navigation/NavigationService';
import linking from './src/navigation/LinkingConfiguration';
const App: React.FC = () => {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<NavigationContainer ref={navigationRef} linking={linking}>
<RootNavigator />
</NavigationContainer>
</PersistGate>
</Provider>
);
};
export default App;
```