m

    miqbaldc

    1 year ago
    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
    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>)
    ) 😄
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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.
    m

    miqbaldc

    1 year ago
    This is my one cents, if I understand you correctly, cmiiw 🙏
    @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) })
    }
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    I don’t think that would even compile –
    observeAsState
    is a composable function, so can’t be called from a
    remember
    lambda.
    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
    m

    miqbaldc

    1 year ago
    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:
    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:
    @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:
    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:
    @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)?
    @Composable
    fun AbcScreen(isChecked: Boolean) {
      val checkedState = remember { mutableStateOf(isChecked) }
    🙏
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    1 year ago
    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.
    m

    miqbaldc

    1 year ago
    Ah I see, can’t be more agreed with you, thanks for confirming and explaining in details :kotlin-intensifies: