I am learning <State hosting> in jetpack compose. I am trying to separate my variable in single func...
k
I am learning State hosting in jetpack compose. I am trying to separate my variable in single function and view logic to separate function. But I am getting weird issue in my code. Can someone guide me on this?
PulsePressure
Copy code
@Composable
fun PulsePressure() {
    var systolicTextFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
        mutableStateOf(TextFieldValue())
    }
    var isSystolicTextFieldValueError by rememberSaveable { mutableStateOf(false) }
    var diastolicTextFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
        mutableStateOf(TextFieldValue())
    }
    var isDiastolicTextFieldValueError by rememberSaveable { mutableStateOf(false) }
    InputWithUnitContainer(
        systolicTextFieldValue,
        isError = {
            isSystolicTextFieldValueError = it
        },
        incrementTextFieldValue = {
            systolicTextFieldValue = it
        })
    InputWithUnitContainer(
        diastolicTextFieldValue,
        isError = {
            isDiastolicTextFieldValueError = it
        },
        incrementTextFieldValue = {
            diastolicTextFieldValue = it
        }
    )
}
InputWithUnitContainer
Copy code
@Composable
fun InputWithUnitContainer(
    textFieldValue: TextFieldValue,
    isError: (Boolean) -> Unit,
    incrementTextFieldValue: (TextFieldValue) -> Unit,
) {
    val maxLength = 4
    Row(
        modifier = Modifier
            .fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically
    ) {
        TextField(
            value = textFieldValue,
            singleLine = true,
            onValueChange = {
                if (it.text.length <= maxLength) {
                    incrementTextFieldValue(it)
                }
                isError(false)
            },
            isError = isError,
            textStyle = RegularSlate20
        )
    }
}
Error on Textfield
Copy code
None of the following functions can be called with the arguments supplied.
z
It looks like you're passing the isError callback to the Boolean isError parameter
k
So how can we fix this ?
I need to update the value and retrieve as well
z
You need to pass a Boolean. Since you're hoisting the state, your isError parameter should probably be a Boolean, and the callback could be called onIsErrorChange. Or, if you don't need to hoist the error state and you can just get rid of the callback in your function and create the mutable state locally.
k
Is this correct?
Copy code
var (isDiastolicTextFieldValueError, updateIsDiastolicTextFieldValueError) = rememberSaveable {
    mutableStateOf(
        false
    )
}
Copy code
InputWithUnitContainer(
    textFieldValue = diastolicTextFieldValue,
    isError = isDiastolicTextFieldValueError,
    updateIsError = updateIsDiastolicTextFieldValueError,
    incrementTextFieldValue = {
        diastolicTextFieldValue = it
    }
)
Method signature change
Copy code
@Composable
fun InputWithUnitContainer(
    textFieldValue: TextFieldValue,
    isError: Boolean,
    updateIsError: (Boolean) -> Unit,
    incrementTextFieldValue: (TextFieldValue) -> Unit,
) {
    ...
}
Copy code
TextField(
    value = textFieldValue,
    singleLine = true,
    onValueChange = {
        if (it.text.length <= maxLength) {
            incrementTextFieldValue(it)
        }
        updateIsError(false)
    },
    isError = isError,
    textStyle = TextStyle(),
)
@Zach Klippenstein (he/him) [MOD] Is this approach is correct?
Or is there any better way ?
z
So that's the right way to hoist state. But you might want to consider deriving the error state from the actual text - right now you've got two sources of truth for the error state, which is going to be harder to maintain and could introduce bugs.
Also you don't need to tag people in threads they've replied to, they'll already get notified.
k
Sorry sir, I would never tag again.
So that's the right way to hoist state. But you might want to consider deriving the error state from the actual text
. I think so is it possible to do that in simple way. I followed this post. Can you give some code snippet?
right now you've got two sources of truth for the error state, which is going to be harder to maintain and could introduce bugs.
Can you please suggest me how can I fix this problem? Thanks
z
Derive the isError value from the text instead of storing it in its own state. Eg
isError = !isTextValid(text)
k
If I change
IsError
to
!isTextValid(text)
. So how can. we notifiy to
TextField(isError = ?)
?
z
It will be recomputed when either the text changes, or any snapshot state
isTextValid
reads changes.
k
Sorry, but I didn't get it. Is there any working example for this?