This seems impossible from my understanding of how compose works, but is it somehow possible? Im cre...
z
This seems impossible from my understanding of how compose works, but is it somehow possible? Im creating a class A that holds B, if B is passed in as State<B> then I can "move" the recomposition scope further in; but if B is read and passed into A as the value itself, then the recomposition scope wraps the entire thing and A is recomposed together with B. Can I somehow pass B "as the value" but still push the recomposition scope further in? K
s
I’m pretty sure your only other option is to pass a lambda with the signature
() -> B
instead and simply invoke this at the level in which you want to read it. And then if you need it as a state I’m pretty sure you can use rememberUpdatedState to turn
() -> B
into
State<B>
smth like:
Copy code
@Composable
private fun B(getB: () -> Int) {
  val b by rememberUpdatedState(getB())
  LogCompositions("B", "b:$b")
}
Do you have some code to share to better understand what you’re trying to do? When you’re saying “I’m creting a class A” do you mean a composable or an actual Class?
z
Thats a cool idea, I never thought about passing lambdas around like that! I dont think its "enough" for my use-case though, for the same reasons that I dont want to pass around State<T> really. To explain my use-case, I pass these values around a lot in my codebase, and a lot of the time theyre also wrapped in other classes. As an example, class A might be wrapped in a LoadingScreen which adds some more behavior to it. Ive tried going down the State<T> route, but inevitably it makes wrapping classes a pain in the ass. Each wrapping class would have to accept either T, or State<T>. I cant really share any code, but I can say that each class A/B, etc, is produced in a @Composable function and is by itself only recomposed when any of its required parameters have changed. The wrapper classes are just constructed in place, with no compose knowledge really. Issue being that since Im passing the values around, A is recomposed when B is recomposed, because thats how things work. I guess I could pass around State<T> and just use rememberUpdatedState for cases where Im only looking to pass the "raw" value instead of another "actual" State<T>. Thats better than just using mutableStateOf in place and creating a ton of state objects. But preferrably there IS a way to get this whole ordeal working?
After thinking a bit more about it, passing around State<T> would be hellish (I have 1759 of these classes 😛).
s
Something I’ve read before here, passing things around as
State<T>
seems to be always discouraged, here is a relevant thread which then also points to another thread 😄 https://kotlinlang.slack.com/archives/CJLTWPH7S/p1640293291045100?thread_ts=1640270959.029600&amp;cid=CJLTWPH7S But as far as doing it automatically for 1759 classes no I don’t know of anything else you can do 😄 Best you can do is make sure that as many things that can be @Stable are in fact @Stable, I don’t have any other ideas myself 😄
z
Great thread! Ironically I think Id run into the same bug at some point by following the State<T> approach, but I think rememberUpdatedState (probably) solves that by reusing the same state instance across recompositions? Ill continue digging homer disappear
s
Just curious, why do you want to push the recomposition scope further? Are there any performance issues caused by this additional recomposition? 🙂 Overall, as long as your models are stable, it is not a big deal to execute some part of composition in these cases, as long as it doesn't happen every frame
z
@shikasd If I can push the recomposition scope further in, a child composable will only recompose itself. Currently, the parent will recompose once in order to update the child as well - and this in turn causes the child to recompose an additional 1-2 times. Usually its smooth, but animations are especially hard to get 100% flowing this way, there are almost some frame drops during the initial animation for a given screen. All models are @Immutable, and that helps, but it seems like I cant avoid the additional recomps happening!
s
Did you try moving animation state reads to layout/draw passes instead? Or the issue is that screen recomposed with unrelated change while animation is in flight?
z
Im using AnimatedContent for animations! The targetState doesnt change during the recompositions, but I think the issue is that since the parent recomposes - the entire child is recomposed too regardless, and that happens to be during animations a lot of the time.
s
Ah, I see, yeah, optimizing here makes sense
z
Thought Id make an update since Ive made some progress! Annotating values that I pass down the tree as @Immutable made a world of a difference. I dont know how compose does it, but effectively it gave me the result that I was looking for - without using State<T>.