Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

MutableStatOf Data Class not creating re-composition in Composable

I am struggling to understand what is the best way to get this to work.
I have some input fields and I created a TextFieldState to keep all the state in one place.
But it is not triggering a re-composition of the composable so the state never updates.
I saw this stack overflow answer on a similar question, but I just find it confusing and it doesn’t make sense to me

Here is the code:

The Composable:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@Composable
fun AddTrip (
addTripVm: AddTripVm = hiltViewModel()
) {

var name = addTripVm.getNameState()
var stateTest = addTripVm.getStateTest()

Column(
    //verticalArrangement = Arrangement.Center,
    modifier = Modifier
        .fillMaxSize()
) {
    Text(text = "Add Trip")
    Column(

    ){

        println("From Composable: ${name.value.value}") //No Recomposition
        meTextField(
            value = name.value.value,
            onChange = {
                addTripVm.updateName(it)
            },
            placeholder = "Name",
        )

}

View Model code:

@HiltViewModel
class AddTripVm @Inject constructor(
    private val tripRepository: TripRepositoryContract,
    private val tripValidator: TripValidatorContract
): TripValidatorContract by tripValidator,  ViewModel() {

    /**
     * Name of the trip, this is required
     */
    private val nameState: MutableState<TextFieldState> = mutableStateOf(TextFieldState())

    private var stateTest = mutableStateOf("");

    fun updateStateTest(newValue: String) {
        stateTest.value = newValue
    }

    fun getStateTest(): MutableState<String> {
        return stateTest
    }

    fun getNameState(): MutableState<TextFieldState> {
        return nameState;
    }

    fun updateName(name: String) {
        println("From ViewModel? $name") 
        nameState.value.value = name
        println("From ViewModel after update: ${nameState.value.value}") //Updates perfectly
    }

}

Text field state:

data class TextFieldState(
    var value: String = "",
    var isValid: Boolean? = null,
    var errorMessage: String? = null
)

Is this possible? Or do I need to separate the value as a string and keep the state separate for if its valid or not?

>Solution :

You don’t change instance of nameState’s value with

 nameState.value.value = name

It’s the same object which State checks by default with

fun <T> structuralEqualityPolicy(): SnapshotMutationPolicy<T> =
    StructuralEqualityPolicy as SnapshotMutationPolicy<T>

private object StructuralEqualityPolicy : SnapshotMutationPolicy<Any?> {
    override fun equivalent(a: Any?, b: Any?) = a == b

    override fun toString() = "StructuralEqualityPolicy"
}

MutableState use this as

fun <T> mutableStateOf(
    value: T,
    policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T> = createSnapshotMutableState(value, policy)

Easiest way is to set

nameState.value = nameState.value.copy(value= name)

other option is to write your own SnapshotMutationPolicy

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading