Aller au contenu

La librairie react-navigation

La librairie react-navigation permet d'utiliser un système de navigation entre les écrans de l'application.

Les écrans affichés successivement sont placés sur une pile ("stack"), ce qui permet de gérer un historique est de revenir aux pages précédentes à l'aide du bouton "Retour".

Ce qui suit est un résumé de la documentation officielle.

Installation des modules

Il y a 4 modules à installer :

npm install @react-navigation/native @react-navigation/native-stack
npm install react-native-screens react-native-safe-area-context

Paramétrage spécifique pour Android

Ouvrir le fichier kotlin front-end/android/app/src/main/java/com/kivappb/MainActivity.kt, et ajouter les 2 blocs indiqués. Une fois modifié, le fichier doit ressembler à :

package com.kivappb;

import android.os.Bundle;  // <-- ici...
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate

class MainActivity : ReactActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {  // <-- ... et là
    super.onCreate(null)
  }

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
   ...
  }

Emballer ("wrap") le point de départ de la navigation

Il faut rajouter un bloc NavigationContainer, puis un bloc Stack.Navigator.

Dans ce second bloc, on liste toutes les pages ("écrans") susceptibles d'être atteintes via le système de navigation :

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

function StartView() {
<NavigationContainer>
  <Stack.Navigator>
    <Stack.Screen name="Home" component={HomeView} />
    <Stack.Screen name="Other" component={OtherView} />
  </Stack.Navigator>
</NavigationContainer>
 ```

## Navigation entre pages

Utiliser `navigation.navigate` ou `navigation.push`.
* `navigation.navigate` ne fait rien si on essaie de naviguer sur la vue déjà affichée
* `navigation.push` navigue vers la vue demandée, même si c'est la même que la vue affichée.
  On a alors plusieurs instances de la même vue dans l'historique de navigation.

```jsx
<Button title="Afficher Détails"
        onPress={() => navigation.navigate('Details')}

Passage de paramètres lors de la navigation

S'il est nécessaire de passer des paramètres à une nouvelle vue, on peut ajouter un objet comme second paramètre de navigation.navigate ou navigation.push :

<Button title="Afficher Détails"
        onPress={() => navigation.navigate('Details', {param1: 'a', param2: 'b'})}

Attention : La documentation mentionne une limitation importante : si les paramètres ne sont pas sérialisables en JSON, la navigation risque de ne pas fonctionner correctement 🤡. Il vaut donc mieux éviter de passer, par exemple, des fonctions (ex. : setUser).

=> Alors, comment faire ?

Réponse : utiliser des contextes ! Il devient ainsi inutile de passer explicitement la pluspart de ces paramètres.

Utilisation des paramètres

Un composant cible de la navigation reçoit deux propriétés :

  • navigation, obligatoire
  • route, optionnelle, seulement si le composant doit recevoir des paramètres via la navigation
function UserView ({ navigation, route }) {
  const { item } = route.params;
  // ...
}

Rendu visuel

Le conteneur de navigation rajoute un en-tête contenant le nom de l'écran en cours, avec une flèche vers la gauche si un retour à l'écran précédent est possible.

Par défaut, l'en-tête affiche l'identifiant de l'écran en cours, mais il est possible de personnaliser son contenu.

Libellé fixe :

<Stack.Screen name="HomeView" component={HomeView}
              options={{ title: 'Users list' }}/>

Libellé contenant un paramètre, via une fonction anonyme :

<Stack.Screen name="UserView" component={UserView}
              options={({ route }) => ({ title: `User ${route.params.item.name}` })}/>