Reputation: 1616
Say in my data class I have variable
var index = 0
In some Composable, the value of this index is observed and modified. So from what I've learned, I need to set up a state in the composable like:
var indexState by remember { mutableStateOf(index) }
Then upon an action (say a button press), I need to update both indexState and index, like:
indexState++
index++
That's troublesome. Is there a good way so that my original variable and the state related to it can be tied together and if one gets updated the other automatically gets updated?
Update: some clarification to my question:
Within the logic of my app, I already have a variable named "index" residing in a data class. Some parts of the UI depends on index or reacts to the change of index. In order for Compose to observe the change of index, I have to introduce a state variable named "indexState" that parallels with index. indexState is solely introduced for the purpose of the UI and is not part of the business logic. Since it has to be introduced, I hope it can at least be easily tied with index so that not much extraneous work is required to manage the extra variables.
Update 2: I learned that the introduction of indexState inside the composable is not needed. I only need to declare index (outside of any composable, preferably as a class member) as:
val index = mutableStateOf(0)
Then in a composable I just use it like:
index.value++
So I don't need the "remember" stuff.
Upvotes: 1
Views: 3225
Reputation:
I don't know where exactly you came across the method that you described, but what you need is state-hoisting.
Basic Principles can be found here. This is how it works.
Let us say you have the variable stored in your viewModel,
var index by mutableStateOf(0) // Use 'by' to avoid writing '.value' every time
Now, you need to create a method in your viewModel to update this variable -- a method that can be called by any code that wishes to modify this variable.
var index by mutableStateOf(0)
fun updateIndex(newIndex: Int){
index = newIndex
}
Now, in your Composable, create two parameters -- one to get the value and another to set it.
@Composable
fun ComposeIsPower(
index: Int,
onIndexUpdate: (Int) -> Unit // It accepts 'Int' and returns 'Unit', like 'void'
){
//Use the Value Here as a normal value,
doSomethingWith(index)
//When you wish to update the value, just call
onIndexUpdate(5) // This sets the index to 5 in the viewModel
}
At the calling site, pass the viewModel's parameters to connect the state-hoisting node, like so.
setContent{
val viewmodel = ... //Initialize ViewModel Here
ComposeIsPower(viewmodel.index, viewmodel::updateIndex)
}
That is pretty much it. You only need a single variable and modifying that will do all the heavy lifting for you -- no need to handle multiple variables like you mentioned above.
Consider taking the codelabs
Upvotes: 0
Reputation: 1473
var index by remember {mutableStateOf(0)}
var indexState by remember {mutableStateOf(0)}
LaunchedEffect(key1 = indexState){
index = indexState
//Automatic update index
}
LaunchedEffect(key1 = Unit){
indexState++
indexState++
indexState++
}
println("indexState: " + indexState)
println("index: " + index)
I/System.out: indexState: 3
I/System.out: index: 3
i wonder why you want to bound two variables, we can find better solution.
Possible another solution;
var index = 0
var indexState by remember {mutableStateOf(0)}
indexState++ //->Update your variable before equalize
indexState++ //->Update your variable before equalize
index = indexState //->Then equalize
println("indexState: " + indexState)
println("index: " + index)
Your viewmodel and composable class should:
class ViewModel (
) : ViewModel() {
var indexState = mutableStateOf(0)
private set
fun updateIndex(){
indexState.value = response.data-> Changes of index.
}
}
@Composable
fun YourScreen(
viewModel: ViewModel,
) {
val index = viewModel.indexState
}
Upvotes: 2