I have a custom object with a boolean value that I want to observe on my screen to change my layout.
Example:
data class Book(isFavorited: Boolean)
@Composable
fun ShowBook(book: Book, onConfirm: (Book) -> Unit){
val bookState = remember { mutableStateOf(book) }
//just an example
val color = if(bookState.value.isFavorited) Color.Red else Color.White
//changing the value of isFavorited, should do recomposition?
Button(onClick { bookState.value.isFavorited = true }){
Text("add to fav")
}
Button(onClick { bookState.value.isFavorited = false }){
Text("remove from fav")
}
Button(onClick { onConfirm.invoke(bookState.value) }){
Text("Confirm")
}
}
If I press the "add to fav" button and set to my bookState a true value for isFavorited, and after that I press "Confirm", the value that I'll receive is still false (default value).
Does Anyone know what's happening?
Because I through that changing the bookState attributions it should recompose and set the correct value to the object.
CodePudding user response:
I did a couple of improvements in your code... It should work now.
In order to perform a recomposition, you must have to create a new instance of the object. In the code below this is done by calling the copy
function just changing the params that you want (in case the class has more fields).
data class Book(val isFavorited: Boolean)
@Composable
fun ShowBook(book: Book, onConfirm: (Book) -> Unit) {
// using "by" to avoid use the ".value" everywhere
var bookState by remember { mutableStateOf(book) }
// just an example
val color = if (bookState.isFavorited) Color.Red else Color.White
// changing the value of isFavorited, should do recomposition?
Button(onClick = { bookState = bookState.copy(isFavorited = true) }){
Text("add to fav")
}
Button(onClick = { bookState = bookState.copy(isFavorited = false) }){
Text("remove from fav")
}
// You don't need the "invoke" here.
// It can be useful if the lambda is nullable:
// onConfirm?.invoke(bookState)
Button(onClick = { onConfirm(bookState) }){
Text("Confirm")
}
}
CodePudding user response:
What's wrong with your code is you remember the book on first composition and it never gets updated because remember{} stores values on first composition, on next compositions or recompositions even if your book parameter changes remember block is never executed. You can verify this by logging
val bookState = remember {
println("Remembered value: $book")
mutableStateOf(book)
}
that's why there is another method called rememberUpdatedState
val bookState = rememberUpdatedState(book)
and if you check source code you will see that
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
mutableStateOf(newValue)
}.apply { value = newValue }
it just updates value by changing mutableState.value
with newValue
or you can manually call bookState.value = book
after remember.
val bookState = remember { mutableStateOf(book) }
bookState.value = book