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