Would anyone giving me a hint about this snippet c...
# compose
m
Would anyone giving me a hint about this snippet code in 🧵 Context:
mutableStateOf(<with initial/default value>)
but the recomposition unable to use the default value
Copy code
fun MyPage(state: MyState) {
   // e.g: uiState has value of true
   val uiState = state.observeAsState().value // this is an API that returns boolean

   TopBar() { // other modifier is omitted
       MyScreen(isChecked = uiState)       
   }
}


@Composable
private fun MyScreen(isChecked: Boolean) {
   CheckBox(
        isChecked = isChecked
   )
}

@Composable
private fun CheckBox(
    isChecked: Boolean,
) {
    val checkedState = remember { mutableStateOf(isChecked) }

    // debuggin the checkedState.value, seems returning "false" instead of "true"
    
    // me trying to update the state 
    Text(modifier = Modifier.clickable { checkedState.value = !checkedState.value })
}
Does my implementation an anti-pattern related to state hoisting and suggested to move the
checkedState
inside
MyPage
or maybe any other alternative suggestion? 🙏 https://dev.to/zachklipp/remember-mutablestateof-a-cheat-sheet-10ma (finish reading this but I’m unable to grasp the idea why it didn’t show the value from parent composable function on this part of code
mutableStateOf(<with default value>)
) 😄
z
There’s a few issues here, but the main one is, as you called out, the second source of truth. If the checkbox state is passed in from the caller, that should be the only source of truth for the state. Your Checkbox composable should take a callback to allow the parent to change its state. Take a look at the implementation of Material Checkbox to see how it does it.
today i learned 1
🙏 1
m
This is my one cents, if I understand you correctly, cmiiw 🙏
Copy code
@Composable
fun MyPage(state: MyState) {
   var checkedState by remember { mutableStateOf(state.observeAsState().value) }
   CheckBox(
        isChecked = checkedState,
        onCheckedChange = { wasChecked -> checkedState = wasChecked }
   )
}

@Composable
private fun CheckBox(
    isChecked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
) {    
    // me trying to update the state 
    Text(modifier = Modifier.clickable { onCheckedChange(!checkedState.value) })
}
z
I don’t think that would even compile –
observeAsState
is a composable function, so can’t be called from a
remember
lambda.
🙏 1
Really, look at the material implementation. Anything i tell you will just be repeating that. E.g. also don’t use
clickable
for checkbox, use
toggleable
today i learned 1
m
Thanks Zach for guiding me through, been looking the official docs implementation, and seems you were right About the
observeAsState
that’s my apologize, I should’ve assign it to a variable first 😄, e.g:
Copy code
val uiState = state.observeAsState().value
var checkedState by remember { mutableStateOf(uiState) }
We were able to solve our issue about the checked state, but we wants to confirm something about below snippet code:
Copy code
@Composable
private fun TextCheck(
    isChecked: Boolean,
) {
    val checkedState = remember { mutableStateOf(isChecked) }

    // debuggin the checkedState.value, seems returning "false" instead of "true"
    Text(text = if (checkedState.value) "Clicked!" else "Not Clicked!")
}
I would like to confirm about this part of code:
Copy code
val checkedState = remember { mutableStateOf(isChecked) }
seems the initial values (after updated from
false
to
true
as
isChecked
modified from highest level composable), in the other hands
checkedState
still using the previous values when doing the recomposition, it’ll show
Not Clicked
--- After modifying it to:
Copy code
@Composable
private fun TextCheck(
    isChecked: Boolean,
) {
    val checkedState = remember { mutableStateOf(false) }
    checkedState.value = isChecked
    Text(text = if (checkedState.value) "Clicked!" else "Not Clicked!")
}
The above snippet will changed from
Not Clicked!
to
Clicked!
(when recomposition) --- Every example on the material and official docs, seems there’s no convention about this snippet below Does this an anti-pattern or (intended not possible to have default values from composable param)?
Copy code
@Composable
fun AbcScreen(isChecked: Boolean) {
  val checkedState = remember { mutableStateOf(isChecked) }
🙏
z
Neither of those snippets look right. There are cases where it makes sense to remember a mutable state where the initial and/or subsequent values are taken from a parameter, but that is specifically the exact thing you do not want to do in this case, from the snippets you’ve posted, because it makes the checkbox useless. Your
CheckBox
component should always just read the
isChecked
value directly, and forward the event handler function. If you’re creating a mutable state that always is synced to the exact value of a parameter, only to then immediately read that state in the composition, there’s no point to having the state at all – just use the parameter directly.
today i learned 1
🙏 1
m
Ah I see, can’t be more agreed with you, thanks for confirming and explaining in details K