Home > database >  MutableStatOf Data Class not creating re-composition in Composable
MutableStatOf Data Class not creating re-composition in Composable

Time:07-03

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:

@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?

CodePudding user response:

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

  • Related