Can someone explain `key(..) { .. }` to me? I do ...
# compose
u
Can someone explain
key(..) { .. }
to me? I do understand
remember(key) { .. }
and side effects etc, but I just cannot wrap my head around it. I never use it in daily practise, yet I see it in some more exotic compose code. It kinda looks like
remember
but .. isn't?
m
have you checked the documentation? https://developer.android.com/develop/ui/compose/lifecycle#add-info-smart-recomposition I think they did a good job explaining it well with a good example
u
I did, but I don' t see the use case, other than LazyXYZ, which does this internally (?)
m
yeah, their use-case isn't that popular. mostly you won't need to use it but it exists for a specific niche scenarios.
u
what do you think is its point here?
m
can't reason about its usage here, StateFlow is supposed to hold one value at a time and whenever its value changes, the underlying molecule presenter will be recomposed with new value and previous value would be disposed from composition anyway. so I'm not sure about it, I don't have an idea about full context behind this snippet
u
nevermind, thanks!
z
There are two main uses I’ve seen for it. Kind of related to this is when you find yourself passing the same keys to many different remembers or effects, or keys derived from other keys. Wrapping the whole thing in a single key function can DRY out that code a bit. And if you’re calling other code that also might have its own state that needs to share the keys, then the key function is the only way to apply that to a whole subtree of composition. This is really useful in navigation containers, eg when you want to make sure an incoming screen has entirely its own state even based on some screen key even if it happens to call the same composables. The other use case is non-lazy lists. Compose doesn’t have enough information to know what an “item” is and keep individual items’ state associated with them if the items are reordered or added/removed. The key function is a grouping/tagging mechanism in that case.
☝️ 2
u
so it's to deduplicate composables which would otherwise be treated as one, due to structural identity?
s
It is to assign identity to the functions that could be treated positionally otherwise. The traditional example is calling something in a loop like this:
Copy code
for (item in list) {
  key (item.key) { ItemContent(item) }
}
Without keys here it will work as well, but if, for example, you remove item N from the list, Compose will try to compose item N + 1 into content that previously was created for slot N and that is way more expensive than just removing the group for item N (which happens with
key
). Internally,
key
is inlined into a "movable" group that can reorder content with that identity within parent, which also is not possible with regular "positional" groups
u
I see so it's override the default behavior of deriving identity from position, if I read it right
e
Yes, and here's a real world example of it, which is also probably the only time I've actually had to use it.