1

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.

ryjtyj
  • 21
  • 4
  • `val onClick = remember {myViewModel.someFunction()}`should fix it. You can also check this [answer](https://stackoverflow.com/a/74700668/5457853) out. After Stability Edit section i mention about ViewModel lambdas and other ways to prevent unnecessary recompositions. – Thracian Aug 23 '23 at 16:10
  • @Thracian thank you for the answer and for the link and the knowledge i get from it, much appreciated! – ryjtyj Aug 24 '23 at 12:47
  • You are welcome. Did it fix the issue you have? – Thracian Aug 24 '23 at 12:54
  • @Thracian, is [this article](https://multithreaded.stitchfix.com/blog/2022/08/05/jetpack-compose-recomposition/) wrong in the section labeled **Option 1 - Method References**, that function references such as `myViewModel::someFunction` are stable if the receiver is stable? I don't see why the compiler would treat `myViewModel::someFunction` differently than `{ myViewModel.someFunction() }`. – Tenfour04 Aug 24 '23 at 13:40
  • @Thracian I'm yet to complete fixing this issue in all places, but your solution indeed works! – ryjtyj Aug 24 '23 at 17:32
  • @Tenfour04 Your link is also helpful, thank you! But as you can see, I was using function references, and the reciever seems to also be stable (please correct me if I'm wrong), but there were still recompositions occuring. – ryjtyj Aug 24 '23 at 17:40
  • @Tenfour04 i read the article now, i actually thought as the author and i recall function references making lambda stable but testing out further i see that without remember some ViewModel, which is unstable itself, are unstable. Because of that the solution works 100% is capturing lambdas inside remember. I will investigate this further – Thracian Aug 25 '23 at 06:22

1 Answers1

1

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)

ryjtyj
  • 21
  • 4