Makina Blog
Créer un menu natif crossplatform avec React Native
Ou comment gérer les composants natifs par plateforme ?
Nous avons déjà découvert React Native ensemble.
Aujourd'hui on va voir comment développer un menu React Native cross platform pour une application simple qui aura une page home et une page favoris.
Android et IOs ont leurs propres guidelines. C'est pourquoi tous les composants de React Native ne sont pas cross platform. Par exemple sur Android, on utilise DrawerLayoutAndroid pour afficher un menu, alors que sur iOS on aura plutôt tendance à utiliser le composant TabBarIos. C'est parfait car c'est justement le point que nous allons illustrer ici.
Pour ce faire, nous devons simplement créer 2 composants avec le même nom. Seulement l'extension sera différente.
Menu.android.js
import { DrawerLayoutAndroid } from 'react-native';
var Menu = React.createClass({
[...]
render: function() {
var navigationView = (
<View style={[styles.layout]}>
<View style={[styles.header]}>
<View style={[styles.headerIcon]}>
<Icon name="md-bulb" size={60} color="#f1c40f" />
</View>
</View>
<Icon.Button style={[styles.menuItem]} name="md-home" color='#455A64' backgroundColor="#fff" onPress={this.goHome} borderRadius={0}>
<Text style={[styles.textItem]}>Home</Text>
</Icon.Button>
<Icon.Button style={[styles.menuItem]} name="md-star" color='#455A64' backgroundColor="#fff" onPress={this.goFavoris} borderRadius={0}>
<Text style={[styles.textItem]}>Starred</Text>
</Icon.Button>
</View>
);
return (
<DrawerLayoutAndroid
ref={'DRAWER_REF'}
drawerWidth={300}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
{this.state.currentView == 'home' ? <ReactNativeView paletteStar={this.state.paletteStar} /> : <Starred selectStar={this.selectStar} /> }
</DrawerLayoutAndroid>
);
}
})
Menu.ios.js
import { TabBarIOS } from 'react-native';
[...]
var Bulb = React.createClass({
render: function() {
return (
<TabBarIOS
unselectedTintColor="yellow"
tintColor="white"
barTintColor="#34495e"
>
<Icon.TabBarItemIOS
title="Home"
iconName="ios-home-outline"
selectedIconName="ios-home"
selected={this.state.currentView === 'home'}
onPress={() => {
this.setState({
currentView: 'home',
});
}}>
<ReactNativeView ref={'HOME'} paletteStar={this.state.paletteStar}/>
</Icon.TabBarItemIOS>
<Icon.TabBarItemIOS
title="Starred"
iconName="ios-star-outline"
selectedIconName="ios-star"
selected={this.state.currentView === 'favoris'}
onPress={() => {
this.setState({
currentView: 'favoris'
});
this.refs['STARRED'].loadStar();
}}>
<Starred ref={'STARRED'} selectStar={this.selectStar} />
</Icon.TabBarItemIOS>
</TabBarIOS>
);
}
})
Gràce à ses extensions (ios.js et android.js), React Native saura qu'il doit utiliser Menu.android.js pour la version android et Menu.ios.js pour iOS.
Notre composant affichera donc selon la plateforme un menu 'TabBar' sur ios et un menu 'Slide' pour android, chacun avec leur propre style.
Des comportements différents
Il faudra faire attention, car justement, ce n'est pas les mêmes composants et donc leurs comportements peut varier.
Ici, lors d'un changement d'option de menu deux scénarios se présentent.
DrawerAndroid : Le composant se recréer à chaque appel, ce qui implique qu'il passera toujours dans notre fonction de cycle de vie ComponentDidMount.
TabBarIos : Les composants ne se rechargent pas chaque fois, ils sont directement créer lors du démarrage de l'application. On ne passera donc pas dans le cycle ComponentDidMount à chaque appel.
Deux choix s'offrent donc à nous, avoir ici aussi un composant home et favoris pour chaque plateforme, ou bien prendre en charge directement dans le composant parent l'action à réaliser lors du changement d'option.
Seulement, l'un des avantages de React Native est justement de pouvoir utiliser le même code pour toutes les plateformes. Du coup, il parait logique d'éviter cette multiplication de composant spécifiques.
Donc dans notre exemple, lors d'un changement d'option sur iOS, on appel directement la fonction du composant enfant pour recharger les favoris : this.refs['STARRED'].loadStar(); Aucune action n'est nécessaire du coté d'Android, car il passera dans ComponentDidMount pour charger les favoris à chaque fois.
On notera que l'on aurait aussi pu utiliser, dans nos composants, le code JS suivant pour gérer nos spécificités :
if (Platform.OS === 'android') {
...
} else {
}
De plus, nous aurions pu utiliser Redux, par exemple, pour nos problèmes de chargement de données.
Conclusion
React Native permet donc de créer des pages spécifiques pour chaque plateforme et d'utiliser des composants natifs pour chacun. Tout ceci se fait simplement et rapidement. Le seul détail qui peut prendre un peu de temps est la partie de création du style des menus, en particulier celui de Android. Mais on verra cette partie plus en détail lors d'un prochain article. Pour aller plus loin, n'hésitez pas à suivre notre formation à react Native !
Formations associées
Formations Mobile
Formation React Native
Aucune session de formation n'est prévue pour le moment.
Pour plus d'informations, n'hésitez pas à nous contacter.
Voir la formationActualités en lien
Générer un fichier PMTiles avec Tippecanoe
Exemple de génération et d’affichage d’un jeu de tuiles vectorielles en PMTiles à partir de données publiques.
Publier une documentation VitePress sur Read The Docs
À l'origine, le site de documentation Read The Docs n'acceptait que les documentations Sphinx ou MKDocs. Depuis peu, le site laisse les mains libres pour builder sa documentation avec l'outil de son choix. Voici un exemple avec VitePress.
Créer une application en tant que composant web avec Stencil
Mise en place dans le cadre de Geotrek, cette solution permet de se passer d'une iFrame pour afficher une application dans n'importe quel site.