Annotation which tells Compose compiler that annotated function is a UI converted from data.
Since Composable UIs are functions, cannot retain its reference.
@Composable
fun SomeListItem(itemList : List<Item>){
Column{
itemList.forEach { item -> SomeUI(item = item) }
}
}
@Composable
fun SomeListItem(itemList : List<Item>){
if(itemList.isEmpty()){
Text("No item")
} else {
Column{
itemList.forEach { item -> SomeUI(item = item) }
}
}
}
Composable Design
No modifications in Composable function
Composable UI functions should not modify properties or global variables to avoid side-effects.
State as parameters
All of the states controls the UI should be passed through parameters. This way, state and the UI is synced whenever the function is called again.
Recomposition happens when a composable is called with different parameters(states) or internal state in function changes.
An observable object integrated within compose runtime
@Composable
fun SomeListItem(itemList : List<Item>){
var selection : MutableState<Item?> = mutableStateOf(null)
Column{
itemList.forEach { item ->
SomeToggle(
item = item,
isSelected = selection.value == item
) }
}
}
Prevents reseting the value of a state and retains it through recomposition which re-invokes the function.
@Composable
fun SomeListItem(itemList : List<Item>){
var selection : MutableState<Item?> =
remember { mutableStateOf(null) }
Column{
itemList.forEach { item ->
SomeToggle(
item = item,
isSelected = selection.value == item
) }
}
}
Use by
keyword to get value of a mutable state directly.
@Composable
fun SomeListItem(itemList : List<Item>){
var selection : Item? by remember { mutableStateOf(null) }
Column{
itemList.forEach { item ->
SomeToggle(
item = item,
isSelected = selection == item
onItemSelected = { item -> selection = item }
) }
}
}
Keep these in mind to avoid side-effects and behave the same through multiple recomposition.
Execution orders are not gueranteed.
@Composable
fun BugProneList(itemList : List<Item>){
var cnt = 0
Column{
itemList.forEach {
item -> SomeToggle(item = item)
cnt++ // Bug-prone with recomposition
}
}
Text("Count : $cnt")
}
Recomposition only affects the UI that depends on the changed state.
@Composable
fun BugProneList(itemList : List<Item>){
Column{
Header() // skipped
Body(list = itemList)
Footer() // skipped
}
}
Recomposition might cancel and run again when the state changes before recomposition finishes.
Composable function should be fast because frequent recomposition might occur through such as animation effects.