Quand on écrit un composable, on utilise une syntaxe indempodente, via une fonction. Pourquoi une fonction = un composable ?
@Composable
fun MyComposable() {
var counter = 1
MyCountableButton(count = counter) {
counter++
}
}
@Composable
fun MyCountableButton(count: Int, onClick: () -> Unit) {
Button(onClick = onClick) {
Text("Click me ${count}")
}
}
MyComposable contient un Ă©tat counter qui est incrĂ©mentĂ© Ă chaque clic sur le bouton.counter nâest pas un Ă©tat, mais une variable locale. En effet, chaque fois que MyComposable est appelĂ©, counter est rĂ©initialisĂ© Ă 1, puisquâune fonction est indempodente, elle produira toujours le mĂȘme rĂ©sultat.Oui, et non.
Compose met à disposition des moyens de gérer les transitions entre les états, et de les rendre persistants.
@Composable
fun MyComposable() {
// Remember va permettre de conserver l'Ă©tat entre les appels, d'oĂč le nom
val counter = remember { mutableStateOf(1) }
MyCountableButton(count = counter.value) {
counter.value++
}
}
@Composable
fun MyCountableButton(count: Int, onClick: () -> Unit) {
Button(onClick = onClick) {
Text("Click me ${count}")
}
}
âïž Pour ceux qui aurait dĂ©jĂ fait du React les
remembersont lâĂ©quivalent desuseMemoen React.
remember permet de conserver lâĂ©tat entre les appelsmutableStateOf permet de dĂ©clarer un Ă©tat mutable, il va permettre de notifier Compose que lâĂ©tat a changĂ©, et de redessiner lâinterface.Il existe plusieurs rememberable :
remember : pour conserver un Ă©tat entre les modifications des variablesrememberSaveable : pour conserver un Ă©tat entre les appels, mais aussi entre les changements de configuration (rotation de lâĂ©cran)rememberCoroutineScope : pour conserver un scope de coroutine -> Important Ă retenirrememberSnackbarHostState : pour conserver un Ă©tat de snackbar... : il en existe dâautresđ§© Remember est utile pour des opĂ©rations de modification dâune variable directes.
âïž Pour ceux qui aurait dĂ©jĂ fait du React les
Launched Effectsont lâĂ©quivalent desuseEffecten React.
Pour effectuer des opérations asynchrones ou plus complexe que des opérations directes, on utilise les SideEffect.
@Composable
fun MyComposable() {
val counter = remember { mutableStateOf(1) }
MyCountableButton(count = counter.value) {
counter.value++
}
LaunchedEffect(counter.value) {
delay(1000) // Simulation d'une opération asynchrone ou complexe
counter.value++
}
}
LaunchedEffect de concert avec rememberCoroutineScope.
fun refreshData() {
// Appel réseau
}
@Composable
fun MyApp() {
val scope = rememberCoroutineScope()
var orderList by remember { mutableStateOf(emptyList<Order>()) }
// shouldRefresh est une fonction qui permet au composable de demander un rafraichissement des données à son parent
OrderScreen(orderList = orderList, shouldRefresh = {
scope.launch {
orderList = refreshData() ?: emptyList()
}
})
// On lance le rafraichissement des donnĂ©es au dĂ©marrage d'oĂč le 'true'
LaunchedEffect(true) {
scope.launch {
orderList = refreshData() ?: emptyList()
}
}
}
Les viewModel sont des classes qui permettent de gĂ©rer lâĂ©tat de lâapplication, et de le partager entre les composants. Câest le niveau ultime de partage de lâĂ©tat.
| Solution | Utilité |
|---|---|
| Variable locale | Pour des opĂ©rations simples, sans partage de lâĂ©tat |
| Remember | Pour conserver lâĂ©tat entre les appels, idĂ©al pour une hierarchie de composants simples |
| SideEffect | Pour des opérations asynchrones ou complexes |
| ViewModel | Pour partager lâĂ©tat entre les composants, idĂ©al pour une application complexe |
Tout est expliqué ici, dans un article trÚs bien fait par Google : State in Jetpack Compose
| CritĂšre | Validation |
|---|---|
Vous savez définir State | [ ] |
Vous avez compris le fonctionnement de Remember | [ ] |
 Vous savez comment et quand utiliser SideEffect | [ ] |
Vous savez comment et quand utiliser ViewModel | [ ] |
 Vous savez définir State Hoisting | [ ] |