La principale librairie pour implémenter la navigation en React Native est React Navigation. Elle supporte les mécanismes natifs standards
npx expo install @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context
import { View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Form from './Form.js';
import Show from './Show.js';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Form">
<Stack.Screen
name="Form"
component={ Form }
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Show" component={ Show } />
</Stack.Navigator>
</NavigationContainer>
);
}
Pour déclencher la navigation, chaque component utilisé en tant que Screen reçoit une prop navigation. navigate(name)
permet d'aller vers une nouvelle page, ou de retourner sur une page existante. Par défaut, si on est déjà sur la page, la navigation n'est pas redéclenchée.
export default function Form({ navigation }) {
function handlePressed() {
if (display.name.trim() == '') {
// ...
} else {
navigation.navigate('Show');
}
}
// ...
}
On peut fournir des paramètre lors de la navigation.
navigation.navigate('Show', display);
import { View, Text, Button, Alert } from 'react-native';
export default function Show({ route }) {
console.log(`Show ${JSON.stringify(route.params)}`);
const display = route.params;
return (
<View
style={{
flex: 1, gap: 16, justifyContent: 'center', alignItems: 'center',
backgroundColor: (display.darkMode ? 'black' : 'white')
}}
>
<Text style={{ color: (display.darkMode ? 'white' : 'black') }}>
{ display.name }
</Text>
{/* ... */}
</View>
);
}
Plusieurs options de configuration disponibles, soit via le NavigationContainer ou directement dans les écrans enfants
import { StatusBar } from 'expo-status-bar';
import { View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Form from './Form.js';
import Show from './Show.js';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<>
<StatusBar style="light" />
<View style={{ flex: 1, backgroundColor: 'red' }}>
{/* View wrapper si backgroundColor dans les components enfants */}
<NavigationContainer>
<Stack.Navigator
initialRouteName="Form"
screenOptions={{
headerStyle: {
backgroundColor: 'seagreen'
},
headerTintColor: 'white',
}}
>
<Stack.Screen
name="Form"
component={ Form }
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Show" component={ Show } />
</Stack.Navigator>
</NavigationContainer>
</View>
</>
);
}
import { StatusBar } from 'expo-status-bar';
import { View, Text, Button, Alert } from 'react-native';
export default function Show({ navigation, route }) {
console.log(`Show ${JSON.stringify(route.params)}`);
const display = route.params;
function handleAgainPressed() {
Alert.alert('Title', 'Message', [
{
text: 'Pop(to root)',
onPress: () => console.log('pressed a')
},
{
text: 'Nav(back)',
onPress: () => console.log('pressed b')
},
{
text: 'Push(new)',
onPress: () => console.log('pressed c')
},
]);
}
return (
<>
<StatusBar style={ display.darkMode ? 'dark' : 'light' } />
<View
style={{
flex: 1, gap: 16, justifyContent: 'center', alignItems: 'center',
backgroundColor: (display.darkMode ? 'black' : 'white')
}}
>
<Text style={{ color: (display.darkMode ? 'white' : 'black') }}>
{ display.name }
</Text>
<Button
title="Again?"
onPress={ handleAgainPressed }
/>
</View>
</>
);
}
Il existe 4 principaux modes de navigation pour les Stack
export default function Show({ navigation, route }) {
{/* ... */}
function handleAgainPressed() {
Alert.alert('Title', 'Message', [
{
text: 'Pop(root)',
onPress: () => navigation.popToTop()
},
{
text: 'Nav(reuse)',
onPress: () => navigation.navigate('Form')
},
{
text: 'Push(new)',
onPress: () => navigation.push('Form')
},
]);
}
{/* ... */}
}
Lorsqu'on retourne sur un écran, on peut recevoir des données de navigation
navigation.navigate('Form', { name: '' })
import { useState, useEffect } from 'react';
export default function Form({ navigation, route }) {
{/*
VS ???
[display, setDisplay] = useState(route.params?.name)
*/}
console.log(route.params);
console.log(display);
// Pour mettre a jour un state avec les params
useEffect(() => {
console.log(`effect ${JSON.stringify(route.params)}`);
if (route.params) {
setDisplay({ ...display, name: route.params.name });
}
}, [route.params]);
{/*
Dans le JSX
<Text>{ JSON.Stringify(display) }</Text>
*/}
}
📚 React Navigation Params Previous SCreen
useEffect est un mécanisme de React permettant de réagir au changement d'un état, state, en vue de synchroniser avec un élément externe: requête HTTP, timeout/interval, NavigationContainer, etc.
Le second paramètre de la fonction est les dépendances déclenchant l'effet
, absent, chaque render[]
, seulement 1 fois, au premier render[stateA, stateB, ...]
, lors d'un changement d'étatimport { useEffect } from 'react';
export default function Show({ navigation, route }) {
{/* ... */}
useEffect(() => {
navigation.setOptions({
headerTintColor: display.darkMode ? 'black' : 'white',
});
}, [])
{/* ... */}
}