Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a composable recompose while seemingly being stateless (the only passed parameter is a function, not a state)

I'm updating the uiState by calling a corresponding function via clicking the first composable. The second composable recomposes because of it, although it doesn't take any state parameters, only another function.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyScetchApplicationTheme {
                Screen(MyViewModel())
            }
        }
    }
}

@Composable
fun Screen(myViewModel: MyViewModel) {
    val myUiState by myViewModel.uiState.collectAsState()

    Column {
        MyBox(myViewModel::changeParameter)       // when clicking this
        MyBox(myViewModel::changeOtherParameter)  // that recomposes
        MyBox{ }                                  // but that one doesn't
        Text("${myUiState.otherParameter}")  // and neither does that one
    }
}

@Composable
private fun MyBox(function: () -> Unit) {
    Box(
        modifier = Modifier
            .padding(20.dp)
            .size(80.dp)
            .background(Color.Gray)
            .clickable { function() }
    )
}

class MyViewModel: ViewModel() {
    private var _uiState = MutableStateFlow(MyUiState())
    val uiState: StateFlow<MyUiState> = _uiState.asStateFlow()

    fun changeParameter() {
        _uiState.update { it.copy(parameter = !uiState.value.parameter) }
    }

    fun changeOtherParameter() {
        _uiState.update { it.copy(otherParameter = !uiState.value.otherParameter) }
    }
}

data class MyUiState (
    val parameter: Boolean = false,
    val otherParameter: Boolean = false,
)

The same composable without a function as an argument doesn't recompose, so it's the function that somehow triggers a recomposition. _ Why does it happen, and how to avoid this recomposition without ditching the function? My project becomes laggy due to abundance of unnecessary recompositions.

like image 936
Pan Wiewiorka Avatar asked Oct 12 '25 12:10

Pan Wiewiorka


1 Answers

Putting function parameter into remember prevents recomposing:

    val onClick = remember {myViewModel.someFunction()}

Credits to @Thracian for the answer in the comments (some useful links are also there)

like image 130
Pan Wiewiorka Avatar answered Oct 15 '25 05:10

Pan Wiewiorka