What's the best way to communicate values, like a ...
# compose
a
What's the best way to communicate values, like a position, back up the layout tree? I have mutable state in a composition local currently. Is there a better way?
s
Hoisting the state at the higher level where it needs to be used and passing it and its setter down the tree is probably what you want to do. Passing it as locals then creates this implicit dependency on the local being there which usually becomes a problem the more you do it.
a
I've moved away from passing functions and state down leaf node after leaf node after leaf node until it gets to the relevant leaf node and am now using a UI state object shared by a composition local. I eneded up putting the position in that state object and getting the relevant leaf node to react. I think my bigger problem was that I thought I needed to pass the position back up the tree, however, since I think I can just use a custom layout in my first node to create an absolutely positioned composable without putting the composable near the root of the tree,
s
I don’t want to be judgemental here, but if you do this a lot, and you pass stuff through CompositionLocals instead of simply passing stuff through the parameters (and wrapping them in simple classes when they get too big just as you described) I’d imagine this’d eventually result in so many implicit dependencies that it’d become unreasonable to keep track of what needs to be passed in which parts of the hierarchy in a completely unsafe way which is CompositionLocals. Here’s some more thoughts on this if you’d like #1, #2. But you do you, as long as I don’t have to work on a codebase which uses CompositionLocals in order to pass simple stuff down the composables line 😅
a
You don't need to keep track of what needs to be passed because the UI state objects are defined in the default parameters.
s
In the default parameters of what?
a
The composibles
s
So the composables have a default param that looks smth like this?
fun composable(stateLocal: MyCompositionLocal = DefaultMyCompositionLocal)
? Or how does it look like?
a
Yeah like that. Except I go a bit further.
Copy code
fun composable(someState: String = DefaultMyCompositionLocal.current.someState) {
}
I do a similar thing with methods in my state objects/event objects.
It's basically the pattern used in SwiftUI with environmentalObjects. You can see that in Jetbrain's SwiftUI KMM example.
s
But then your original message “I’ve moved away from passing functions and state down leaf node after leaf node after leaf node until it gets to the relevant leaf node” isn’t relevant anymore since you are in fact passing them down through the parameters again. Why not simply pass a
SomeState
object down the tree instead of
SomeStateCompositionLocal
then? I don’t see what you gain from the CompositionLocal. Plus the problems that I mentioned above still exist, with potentially the composables not being in the correct part of the tree where your Composition local is not provided and getting a runtime crash instead of a compile-time one, or providing multiple ones down different parts of the tree and getting subtle bugs and so on. The fact that it’s something that may happen in SwiftUI doesn’t mean it’s good to replicate here as well imo.
a
I don't see the points about bugs. It's basically
Copy code
defineCompLocal {
  comp2()
}

fun comp2() {
  comp3()
}

fun comp3(state = compLocal.current.state) {
  // use state
}
instead of
Copy code
var state = "something"

comp2(state)

comp2(state) {
  comp3(state)
}

comp3(state) {
  //finally use state
}
Yeah you need the comp locals to be in the correct tree yeah, but my comp locals are at the root, so no real problem. If you hate it, that's fine my friend!
s
Yes, plus in previews you gotta make sure to provide the local which again would be a runtime failure instead of a compile time one. And my point about bugs was if you're providing those locals at different places, but if they're simply global instances at the root that's fine https://kotlinlang.slack.com/archives/CJLTWPH7S/p1661112258266989?thread_ts=1661100732.590039&cid=CJLTWPH7S As you said I don't need to agree, I just wanted to give a couple of thoughts so that if anyone else wants to try out this idea they know what they're getting themselves into