I have a stupid question. If we remember some value and save it to a variable like this `var foo = r...
f
I have a stupid question. If we remember some value and save it to a variable like this
var foo = remember { "hello" }
, when we mutate the variable (
foo = "world"
) it won't save it to next recomposition, right? We just mutate the variable in the current function scope.
I am unsure because I know I've done something like this in my early compose experiments and it worked but I know it shouldn't šŸ˜…
And I am writing article about compose basics and I want to be sure I don't write something stupid.
w
I believe so, in your case you have to do
foo.value = newValue
and to access the value with
foo.value
. To use the Delegate you have to use the `by`:
Copy code
var foo by remember { mutableStateOf("hello") }
        foo = "newValue"
f
I am not using
State
tho so there is no
foo.value
and no delegate.
šŸ¤” 1
j
In ā€œtheoryā€ yes. But IMHO it’s not good practice because composable function calls can be run in any order by the compose runtime. If you rely on changing
foo
the way you mentioned, it will be difficult to ensure all composable functions that have
foo
visible in their scope see the same mutated value of
foo
. If you need mutable state you should remember a
mutableStateOf("hello")
.
f
Maybe I didn't explain myself properly. I know I shouldn't do this and I would never do. In my article I am trying to explain the meaning of
remember
and
State
separately because I don't want the reader to understand
remember { mutableStateOf() }
as one thing. While explaining this I realized that I am not 100% sure that I know how it will behave so I just wanted to make sure šŸ˜„
it will be difficult to ensure all composable functions that haveĀ 
foo
Ā visible in their scope
So if some inner composable function recomposes, will it get the new value of
foo
variable?
j
So if someĀ innerĀ composable function recomposes, will it get the new value ofĀ 
foo
Ā variable?
I think the safe answer here is ā€œit’s not possible to know it reliablyā€, but I feel like I’m reaching the edge of my knowledge here, I’m sure somebody else might give a better answer. Updated answer: Yes, but only if it recomposes after
foo
has been mutated.
šŸ™ 1
a
remember
always returns the same instance produced by executing the block in the first composition.
foo
is just a pointer so changing the value
foo
points to doesn't affect what
remember
returns.
So if someĀ innerĀ composable function recomposes, will it get the new value ofĀ 
foo
Ā variable?
The inner function captures the pointer so I think the answer is yes.
f
I think that's all I need. Thank you both @julioromano @Albert Chang šŸ‘Œ
(I almost wrote "closing this issue" šŸ¤¦ā€ā™‚ļø )
j
@Albert Chang Isn’t it possible that the inner function gets re-run directly by compose (i.e. only the inner function is re-run, the outer function is not)? Perhaps because the inner function was reading some other snapshot state object which has changed. (Sorry if the question sounds weird, I’m deliberately trying to test my mental model of the subject.)
a
@julioromano As I said what the inner function captures is the pointer which always points to the latest value.
j
Got it, so if the code was actually:
Copy code
var foo = remember { "hello" }
  foo = "newValue"
It means that any other code will see ā€œnewValueā€, so in this case the
remember
call is useless, it’s just polluting the composition by adding a ā€œhelloā€ string to it that will never be read. I get that @Filip Wiesner is asking this for teaching purposes, I just wanted to be sure such a ā€œpatternā€ would never be actually useful in real life.
f
in this case theĀ 
remember
Ā call is useless, it’s just polluting the composition by adding a ā€œhelloā€ string to it that will never be read
(nitpicking a little bit) It will be read exactly once and assigned to the variable but other than that, that's exactly how I understand it.
j
Ah yes, during recompositions the memoized ā€œhelloā€ will be read from the composition and assigned to
foo
briefly, just to be overwritten by ā€œnewValueā€ right after.
šŸ‘Œ 1
f
For sake of completeness, here is the section of the article I was writing:
šŸ‘ 1
j
The case I was thinking about earlier is similar to @Filip Wiesner ’s last example but adds another composable (a
Button
) that recomposes on each click (recomposition is triggered thanks to
someState
snapshot state object):
Copy code
@Composable
private fun MyOuterComposable() {
    Column {
        var searchValue = remember { "" }
        var someState by remember { mutableStateOf(".") }
        OutlinedTextField(
            value = searchValue,
            onValueChange = { searchValue = it },
        )
        Button({ someState = someState.plus(".") }) {
            Text("someState: $someState - searchValue: $searchValue")
        }
    }
}
The value of
searchValue
that
Button
displays depends on when
Button
has been recomposed. If it recomposes after
searchValue
has been mutated then it will show the mutated value, otherwise not. Since the order in which composables (i.e.
Button
in this case) recompose may not always be reliably predicted, we can’t be sure which value of
searchValue
will be read by
Button
. Disclaimer: this kind of code is just for learning purposes, it should never be used in production.
f
Learning about Compose is so exciting! šŸ˜„ I can't wait for when I'll use it on a real project.
s
Yes this works as expected (which is not to work due to string immutability), though it's not a recommended practice for the reasons outlined above. If you put a mutable value in there, you can use it to update stored values without triggering recomposition, which we do using https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]kotlin/androidx/compose/ui/node/Ref.kt?q=Ref%3CT%3E%20compose
Which I can't find a usage of in remember anywhere anymore
TL;DR don't do that unless you're really really sure you know what you're doing and you're building alternative effects like
Reducer(...)
or
Prev(...)
šŸ™‚
j
What are
Reducer(...)
Ā orĀ 
Prev(...)
? Are they something in compose? Or you mean Reducer as in Redux ?
s
You can make a composable function that does reducer behavior, which will require access to the previous value; none of this is part of Compose but it's possible to write and you'll need a Ref somewhere in there šŸ™‚
😮 1