Naviguer entre les écrans d’une application React Native

Découvrons comment mettre en place divers écrans de notre application React Native et le routeur/navigation entre ces écrans.

Une fois le repo cloné, il vous suffit d’un npm install pour installer toutes les librairies nécessaires.
Nous parlons ici de la librairie react-navigation en version 3. Sa documentation est disponible ici.

Créer une navigation inter-écrans dans React Native

Naviguer entre les écrans d'une application mobile React Native avec react-navigation

L’usage de React Navigation

Une application mobile est en fait une succession d’écrans. Imaginez une pile d’écrans, l’écran actif (visible) étant en haut de la pile et le tout premier écran navigué par l’utilisateur étant en bas de pile.

Le navigateur de « piles » d’écrans de React Navigation est un outil pratique dans le développement d’une application React Native pour créer un système de navigation entre ces écrans et profiter d’un routeur pour diriger l’utilisateur au bon endroit.

Si l’application n’utilise qu’une pile d’écrans, alors la logique est sensiblement la même que celle des navigateurs web et de leur gestion de navigation entre les pages : l’application React Native ajoute ou supprime des éléments de la pile d’écrans navigués, et on peut à tout moment revenir en arrière (avant dernier écran en haut de notre pile) voire en avant. Le résultat : l’utilisateur voit des écrans différents dans son application.

Une différence clé cependant : React Navigation gère lui-même les mouvements et animations que les utilisateurs attendent sur Android et iOS pour pouvoir naviguer librement entre les écrans, comme dans tout autre application mobile de leur système. L’intégration est donc parfaite et l’expérience utilisateur est optimale.

Mise en place de la pile (stack) d’écrans

La logique fondamentale est très bien décrite dans la documentation officielle de la librairie.

Mise en place du conteneur d’applications avec un switch entre les piles

L’objectif est que React Navigation nous fournisse un composant qui sera chargé dans le composant principal <App /> de notre application, dans App.js.

Mais avant cela, on va devoir enregistrer nos 2 piles contenant chacune un ensemble précis d’écrans : l’un juste pour le login, l’autre pour le cœur de l’app.

Enregistrer nos groupes d’écrans avec createStackNavigator

import Login from "./src/screens/Login/Login";
import BeersList from "./src/screens/BeersList/BeersList";
import BeerAdd from "./src/screens/BeerAdd/BeerAdd";
import Profile from "./src/screens/Profile/Profile";

/**
 * Our LoginStack which contains only the Login screen
 */
const LoginStack = createStackNavigator({
	Login: {
		screen: Login,
	},
});

/**
 * Our main AppStack with every app screens, accessible once user is logged in
 */
const AppStack = createStackNavigator({
	BeersList: {
		screen: BeersList,
	},
	BeerAdd: {
		screen: BeerAdd,
	},
	Profile: {
		screen: Profile,
	},
});

Ci-dessus, on utilise la fonction createStackNavigator() pour enregistrer nos 2 piles (stacks). L’un contient seulement un écran de Login, alors que le second contient nos 3 écrans principaux de l’application : BeersList, BeerAdd et Profile.

Le switch de piles avec createSwitchNavigator

Le but du SwitchNavigator est de n’afficher qu’un seul écran à la fois. Par défaut, il ne gère pas les actions du bouton « retour » et il réinitialise les routes à leur state initial lorsque l’on passe d’une pile d’écrans à l’autre. C’est précisément le comportement attendu lors d’une authentification utilisateur.

https://reactnavigation.org/docs/en/switch-navigator.html

Nous disposons désormais de deux piles distinctes d’écrans : l’une (LoginStack), très simple, ne comprend que l’écran d’authentification utilisateur. L’autre (AppStack), plus complexe, comprend le cœur de notre application et ses écrans principaux.

import Loading from "./src/screens/Loading/Loading";

/**
 * Our AppContainer that will load a quick Loading screen in charge of choosing if we display the Login or App stack
 */
const AppContainer = createAppContainer(
	createSwitchNavigator(
		{
			Loading: Loading,
			Login: LoginStack,
			App: AppStack,
		},
		{
			initialRouteName: "Loading",
		}
	)
);

L’interrupteur createSwitchNavigator() va nous permettre de marquer une séparation claire entre ces deux piles : si l’utilisateur n’est pas connecté, il accède au premier stack. Il ne peut évidemment pas accéder au deuxième stack des écrans principaux.

A contrario, s’il est correctement authentifié, il accèdera au second stack pour naviguer dans les écrans principaux de l’application. Il n’a pas besoin d’accéder à l’écran d’identification, vu qu’il est déjà connecté.

Les 2 piles (Login/App) sont distinctes : une fois connecté, l’utilisateur qui est rentré dans l’AppStack ne pourra pas revenir sur l’écran unique du LoginStack via un clic sur son bouton « retour ». Et inversement, s’il se déconnecte, le bouton « retour » ne lui permettra pas de revenir vers les écrans principaux de l’application.

Notons alors un paramètre important de ce switch est initialRouteName : il indique à l’application l’écran par défaut (le premier) à afficher pour ce switch. Dans notre cas, on veut donc commencer par l’écran de Loading qui décidera où diriger l’utilisateur dès qu’il ouvre l’appli.

L’écran-cerveau du switch

Ajoutons un troisième écran à ce switch : l’écran Loading. Il n’a aucun intérêt du point de vue utilisateur, mais c’est lui le cerveau de ce switch.

class Loading extends Component {
	componentDidMount() {
		const isLoggedIn = false;
		this.props.navigation.navigate(isLoggedIn ? "App" : "Login");
	}

	render() {
		return <Text>Loading screen</Text>;
	}
}

Dans sa méthode componentDidMount, il vérifie si l’utilisateur est connecté. S’il l’est, on l’envoie vers sa liste de bières. Pas encore connecté ? On lui affiche l’écran d’identification. A l’ouverture de l’appli, cette logique se fera instantanément et l’utilisateur n’y verra que du feu !

Ici, on force l’application à charger l’écran de login en indiquant que l’utilisateur n’est pas connecté via une variable isLoggedIn = false. Cette logique évoluera à l’avenir.

Le conteneur d’appli créé par createAppContainer

class App extends Component {
	render() {
		return <AppContainer />;
	}
}

export default App;

Maintenant que nos 2 piles d’écrans sont prêtes, il suffit d’utiliser la fonction createAppContainer() pour créer un nouveau composant intelligent <AppContainer />. Lorsque l’application sera ouverte, la logique du switch décrite ci-dessus sera lancée, et l’utilisateur accèdera immédiatement à l’écran adéquat selon son authentification.

Naviguer entre les écrans via une interaction dans les composants

Nos routes et piles sont prêtes. Il suffit désormais de relier certains boutons pour qu’il redirige l’utilisateur vers tel ou tel écran.

Chaque écran enregistré plus haut va recevoir de react-navigation une prop navigation (documentation disponible ici).

Cette prop this.props.navigation peut être exécutée à tout moment par votre composant pour :

  1. naviguer vers un écran spécifique avec this.props.navigation.navigate("nomDeLecran"), comme on le fait plus haut dans le composant Loading
  2. revenir à l’écran précédent avec this.props.navigation.goBack(), comme on le fait dans la <TopBar /> après un clic sur l’icône de retour

Et voila ! Nous avons maintenant avancé le développement de notre application React Native en mettant en place ses fondations. Les écrans et la navigation inter-écrans est prête. Passons maintenant à l’architecture de nos données et la mise en place de notre store Redux.


Vous avez aimé cet article ?

Partagez-le sur vos réseaux sociaux en guise de remerciement :)


1 commentaire

Laisser un commentaire