Les développeurs se demandent souvent s’il faut utiliser des composables stateful ou stateless dans Jetpack Compose.
Choisir la mauvaise approche peut compliquer la maintenance et réduire la testabilité des applications.
Cet article explore les avantages des composables stateless et comment les intégrer efficacement pour des applications robustes.
Créez des interfaces modernes et réactives avec JetPack Compose!
Introduction
Lors de la création d’interfaces utilisateur dans Jetpack Compose, les développeurs sont souvent confrontés à un choix : créer des composables « stateful » (avec état) ou « stateless » (sans état). Cette distinction est essentielle pour construire des applications efficaces, maintenables et facilement testables.
Comprendre les Composables Stateful et Stateless
Un composable stateful est un composant d’interface utilisateur qui conserve son propre état. Cela signifie qu’il gère en interne des données qui peuvent changer au fil du temps, ce qui entraîne une recomposition de l’interface.
Exemple de composable stateful :
@Composable
fun StatefulCounter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
Voici ce que renvoie le programme :
Dans cet exemple, le composable StatefulCounter conserve l’état count en interne. Chaque fois que le bouton est cliqué, l’état est mis à jour, ce qui déclenche une recomposition du texte affiché.
Un composable stateless, en revanche, ne conserve pas d’état en interne. Il reçoit toutes les données nécessaires via ses paramètres, ce qui le rend plus flexible et plus facile à tester.
Exemple de composable stateless :
@Composable
fun StatelessCounter(count: Int, onIncrement: () -> Unit) {
Button(onClick = onIncrement) {
Text("Count: $count")
}
}
Ici, StatelessCounter ne gère pas l’état count. Il se contente de l’afficher et d’exécuter une action lorsqu’il est cliqué. L’état et la logique sont délégués à l’extérieur du composable.
Avantages de l'Utilisation des Composables Stateless
Élément | Description |
---|---|
Meilleure Testabilité | Les composables stateless sont plus faciles à tester car ils ne dépendent pas d’un état interne. Il suffit de fournir les données nécessaires en entrée pour vérifier la sortie. |
Prévisualisation Simplifiée | Les composables stateless sont plus faciles à prévisualiser avec la fonction @Preview, car ils n’ont pas d’état dynamique. Cela permet de vérifier rapidement le rendu avec différentes valeurs. |
Réutilisabilité | Un composable stateless est plus réutilisable car il ne conserve pas d’état propre, permettant son usage dans divers contextes avec des données variées sans risque d’effets secondaires liés à l’état. |
Meilleure Testabilité
Les composables stateless sont plus faciles à tester car ils ne dépendent pas d’un état interne. Pour tester un composable stateless, il suffit de lui fournir les données nécessaires en entrée et de vérifier la sortie.
Exemple de test d’un composable stateless :
@Composable
fun PreviewStatelessCounter() {
StatelessCounter(count = 10, onIncrement = {})
}
Avec cette approche, le test du composable est simplifié car il suffit de vérifier l’affichage avec des valeurs prédéfinies.
Prévisualisation Simplifiée
Dans Jetpack Compose, la fonction de prévisualisation (@Preview) est plus facile à utiliser avec des composables stateless. Puisqu’ils ne dépendent pas d’un état dynamique, vous pouvez rapidement afficher et vérifier le rendu de l’interface avec différentes valeurs.
@Preview
@Composable
fun PreviewStatelessCounter() {
StatelessCounter(count = 5, onIncrement = {})}
Reutilisabilité
Un composable stateless est plus réutilisable, car il ne conserve pas d’état propre. Vous pouvez l’utiliser dans différents contextes avec des données différentes sans avoir à vous soucier des effets secondaires liés à l’état.
Transformer un Composable Stateful en Composable Stateless
Exemple Pratique
Prenons un exemple où nous avons un composable stateful qui affiche une liste d’articles, et transformons-le en composable stateless.
Composable Stateful :
@Composable
fun ArticleList(viewModel: ArticleViewModel) {
val articles by viewModel.articles.observeAsState(emptyList())
LazyColumn {
items(articles) { article ->
Text(article.title) } }}
Transformation en Composable Stateless :
@Composable
fun ArticleList(articles: List, onArticleClick: (Article) -> Unit, onFavoriteClick: (Article) -> Unit) {
LazyColumn {
items(articles) { article ->
ArticleItem(
article = article,
onClick = { onArticleClick(article) },
onFavoriteClick = { onFavoriteClick(article)
} ) } }}
Voici ce que renvoie le programme :
Dans cet exemple, ArticleList est désormais stateless. Il reçoit la liste d’articles ainsi que deux callbacks pour gérer les clics sur un article et sur le bouton « favori ». Le ViewModel n’est plus directement intégré dans le composable, ce qui améliore la flexibilité et la testabilité.
Implémentation des Callbacks
Pour compléter cette transformation, nous devons nous assurer que les callbacks sont correctement implémentés et passés au composable stateless.
@Composable
fun ArticleScreen(viewModel: ArticleViewModel = viewModel()) {
val articles by viewModel.articles.observeAsState(emptyList())
ArticleList(
articles = articles,
onArticleClick = { article ->
// Gérer le clic sur l'article
},
onFavoriteClick = { article ->
// Gérer le clic sur le bouton "favori"
}
)
}
Voici ce que renvoie le programme :
Élément | Description |
---|---|
ArticleScreen | Composable principal affichant une liste d’articles en utilisant les données du ViewModel. |
ViewModel | ArticleViewModel injecté par défaut pour gérer les données et la logique métier des articles. |
Observateur d’État | Utilise observeAsState() pour observer la liste d’articles depuis le ViewModel. |
ArticleList | Affiche les articles et gère les interactions comme le clic sur un article ou sur le bouton « favori ». |
Gestion des Interactions | Définit les actions à réaliser lors des clics sur les articles et les boutons favoris, permettant de gérer les interactions utilisateur. |
Impact sur la Testabilité et la Maintenance
Tests Unitaires Simples
En séparant la logique d’état du composable, vous pouvez écrire des tests unitaires plus simples et plus ciblés. Par exemple, pour tester ArticleList, vous n’avez plus besoin de simuler un ViewModel complexe.
Test d’un composable stateless :
@Test
fun testArticleList() {
composeTestRule.setContent {
ArticleList(
articles = listOf(Article("Test Article")),
onArticleClick = {},
onFavoriteClick = {}
)
}
composeTestRule.onNodeWithText("Test Article").assertExists()
}
Voici ce que renvoie le programme :
Conclusion
La distinction entre composables stateful et stateless est un concept fondamental dans Jetpack Compose. Opter pour des composables stateless chaque fois que possible améliore la testabilité, la maintenabilité et la réutilisabilité de votre code.
Formez-vous gratuitement avec Alphorm !
Maîtrisez les compétences clés en IT grâce à nos formations gratuites et accélérez votre carrière dès aujourd'hui.
FAQ
Qu'est-ce qu'un composable stateful ?
Qu'est-ce qu'un composable stateless ?
Comment transformer un composable stateful en stateless ?
Quels sont les avantages des composables stateless ?
Pourquoi choisir des composables stateless pour les tests ?
Conclusion
La distinction entre composables stateful et stateless est cruciale pour optimiser la testabilité et la réutilisabilité du code. Quelle approche préférez-vous dans vos projets Jetpack Compose ?