What's the consensus on providing your uiState via...
# compose
c
What's the consensus on providing your uiState via
CompositionLocalProvider
to other composables from your main composable? I assume this would be good for composables that you don't plan on re-using and are coupled tightly to that uiState. Rather than passing in my uiState to every composable that needs it. Or is this already a smell because each composable should only have things passed into it it needs? I've thought about this when let's say composable B needs to send data to composable C from composable A (from the uiState) and rather than pass in 8 things to composable B, I'd rather pass in a uiState so I have access to everything I need. (If a composable only needs 1-2 things then it makes sense to only pass those, but for composable dependencies that need 7-8 fields does this make sense to do?)
z
It’s a smell for the reason you suspect. It creates hidden dependencies, which make your composables more coupled and less testable. There are other ways to avoid having to write excessive wiring in intermediate composables (namely, using slots).
👍 4
The official composition local docs talk about this, but the advice given on this channel (it comes up a lot) is often much stronger.
c
I hear a lot of talk about slots, and I need to read more on it, but those are just a collection of pre-defined Material based composables we can use right? If everything is custom I don't think the slot API would work for me 😢. As far as testing goes I'm not testing every individual composables but rather the main composable multiple times with different uiStates to confirm every scenario. It actually wouldn't hinder testing at all but I would like a better way to pass variables I need down into lower composables
z
No, a “slot” is just shorthand for “a parameter that is a composable function”
🙏 1
Ie Column’s content parameter is a slot
👍 1
c
I've been using them and didn't even know it 😅
z
Yea it’s jargon. But it kinda makes sense because it’s a very specific type of parameter. Like a button almost tangibly has a “slot” you can stick some text in
Doesn’t help that compose also has something called a “slot table” which is completely unrelated lol
👆 2
c
Yeah which is really cool. I really like the flexibility it provides when creating content
lol for subComposeLayout right? Edit: After reading about it it's a whole 'nother can of worms. oof
z
The slot table is the underlying data structure that all compositions use to store information about the call graph and things like remember
Basically most things that fall under “the state of the current composition”. That’s probably too broad a category. Anyway, we digress lol
👍 1
c
Thanks for the info! I'll look into some other ways to pass data around 👍
z
Think about whether you can factor out some things like internal layouts you’ve had to make, or logic around animations or other complex code. If you can get those out of your “main” composables that actually know about your domain-specific models, then those composables get super readable.
And you’ll probably have composables that are easier to unit test and stuff in the process!
Here’s kind of an example (ignore all the “workflow” stuff lol). I pulled the animation code (stolen from the sample in the official docs) out into a separate composable (
AnimatedContent
) to keep the actual semantic content of the function more clear. It’s also more reusable that way, but reuse isn’t the primary goal here. The animation details were just too complex and not related to the main purpose of this particular function, which is to define what data to show.
c
You know what, the slot talk actually made its way through this thick brain. I know what I want to do now. You're right I can hoist the state out of each composable and just use a slot and send the info from the mainComposable via Basic values like String, Int, Boolean, etc. That's gonna be much cleaner. Thanks Zach 🙂
👍🏻 1
z
“Slot Talk” good podcast name lol
💯 1
c
seeing that I'd think it's a podcast for gambling junkies but...I'd probably still click it to listen lol
k
UI state as composition locals is the new global static uber variables
☝️ 2
☝🏻 1
a
I have my state in a view model, and I use a
CompositionLocalProvider
as a default parameter to give my composables access to those. My functions basically look like this:
Copy code
@Composable
fun SomeComp(
  someParam: String,
  myVM: MyViewModel = LocalAppViewModel.current,
) {
}
Initially, I was passing state and callbacks into every Composable but that got tiring. So my business logic and my state now live in my view models, and those are passed to every Composable as a default parameter. This means the composables are tied to the view model. Yet it's no problem. Firstly, these aren't reusable components. Secondly, when needed, refactoring them to take two extra params instead of the ViewModel is less work than figuring our their behaviour before I code them and before I iteratively test their UI behaviour. I'm happy to receive any feedback.