'Type mismatch in compose state hoisting

I am attempting to get one property to bind between a ViewModel and a @Composable.

I am getting the following error

Type mismatch. 
Required:String 
Found:MutableState<String.Companion>

I don't understand what I am doing wrong.

//Reusable input field
@Composable
fun MyTextField(
    value: String,
    onValueChange: (String) -> Unit,
    placeHolder: String
    ) {
    OutlinedTextField(
        value = value,
        onValueChange = onValueChange,
        placeholder = {Text(placeHolder)},
    )
}


// ViewModel
class MyViewModel : ViewModel () {
    var MyVariable = mutableStateOf(String)
}


// stateful comp
@Composable
fun MyScreen(
    viewModel: MyViewModel = MyViewModel()
) {
     MyContent(
        myVariable = vm.myVariable,
        setMyVariable = { vm.myVariable = it }
    )
}

// stateless Comp
@Composable
fun MyContent(
    myVariable: String,
    setMyVariable: (String) -> Unit
)
    {
        Column() {
    
            MyTextField(value = myVariable, onValueChange = setMyVariable, placeholder = "Input Something")

            Text("Your variable is $myVariable" )
    }




Solution 1:[1]

You are initializing your variable as a MutableState<T> type data-holder.

What you've posted in the question won't even compile but this is what I assume you did in your actual code

var myVar = mutableStateOf ("")

Now, mutableStateOf("") returns a MutableState<String> type object, which you are passing around in your methods.

On the other hand, your methods expect a String type object, not MutableState<String>. Hence, you could either extract the value from your variable and pass that around,

myVar.value

Or do it the preferred way, and use kotlin property delegation.

Initialize the variable like this

var myVar by mutableStateOf ("")

The by keyword acts as a delegate for the initializer and returns a String value instead of a MutableState<T>. This updates and triggers recompositions just as it's other counterpart but is far cleaner in code and keeps the boilerplate to a minimum.

Also, you seem to be pretty new to compose and kotlin, so consider taking the Compose pathway to learn the basics. Just look it up and the first official Android developers link will take you there.

EDIT: FINAL ANSWER

ViewModel

ViewModel{
 var v by mutableStateOf ("")
 fun setV(v: String) {
   this.v = v
 }
}

Composable calling site

MyComposable(
 value = viewModel.v
 onValueChange = viewModel::setV
)

Composable declaration

fun MyComposable (
 value: String,
 onValueChange: (String) -> Unit
) {
 TextField (
  value = value
  onValueChange = onValueChange
 )
}

This is the proper state-hoisting linking where the state variable is updated properly and hence, read well. Also, sir, you'd know what state-hoisting is if you'd actually read through the docs and taken the codelabs. I'm serious, TAKE the codelabs (in the Compose pathway). That's the reason your question was downvoted so many times, because you use terms like state-hoisting as if you understand it, but then you don't have half the implementation that it promotes.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1