https://kotlinlang.org logo
t

Tony Mykhaylovsky

11/17/2020, 4:27 PM
Besides using a view model, how can I set a State variable from a child View?
I have a boolean defined as isMap and it's set to false by default. I would like to be able to change that to true from a child view. In SwiftUI, this can be accomplished by creating a binding object on the child view. Not sure how to do it in Jetpack Compose. THANK YOU!
s

Se7eN

11/17/2020, 4:31 PM
Copy code
@Composable
fun Parent() {
    var state by remember { mutableStateof(false) }
    Child(onSomeEvent = { state = true })
}

@Composable
fun Child(onSomeEvent: () -> Unit) {
    Button(onClick = onSomeEvent)
}
☝️ 4
t

Tony Mykhaylovsky

11/17/2020, 4:32 PM
Wow - so you have to define the function in the parent and pass the event. Otherwise, a viewModel is the alternative?
z

Zach Klippenstein (he/him) [MOD]

11/17/2020, 4:33 PM
Using callbacks to avoid data dependencies between components like that is the recommended best practice.
j

Javier

11/17/2020, 4:33 PM
@Tony Mykhaylovsky I think it is better if you pass the actions to the childs and you keep the ViewModel at the parent
p

ppvi

11/17/2020, 4:33 PM
a viewModel is a less preferable alternative
z

Zach Klippenstein (he/him) [MOD]

11/17/2020, 4:34 PM
You could also do something like pass a
MutableState
down to your child and have the child mutate the state itself, but that increases coupling and is considered more of a bad practice.
a

Adam Powell

11/17/2020, 4:35 PM
if you find you need that kind of guaranteed-synchronous behavior it's often better to define an object or interface you pass to the composable
passing
MutableState<MyData>
around is kind of like passing around
Pair<Foo, Bar>
instead of defining a data class for the abstraction you're trying to represent with it
p

ppvi

11/17/2020, 4:36 PM
I think they're just trying to type less Adam 😁
a

Adam Powell

11/17/2020, 4:36 PM
always 😛
I'm foreshadowing some of the work going into `TextField`s at the moment
t

Tony Mykhaylovsky

11/17/2020, 4:41 PM
Very helpful - thank you all
So if I have a busy Child View, it could potentially have 5 parameter functions?
j

Joost Klitsie

11/17/2020, 4:44 PM
you could make your view composable as well
p

ppvi

11/17/2020, 4:44 PM
you can group them in something called
actions
🔝 1
t

Tony Mykhaylovsky

11/17/2020, 4:44 PM
Both parent and child are composable
j

Joost Klitsie

11/17/2020, 4:45 PM
Copy code
@Composable
fun parent() {
    childContainer(...paremeters) {
         SomeOtherComposable()
    }
}

@Composable
fun childContainer(...paremeters, children: @Composable () -> Unit) {
     SpecialStuff()
     children()
}
t

Tony Mykhaylovsky

11/17/2020, 4:46 PM
Overwhelming amount of help - thank you 🙂
j

Joost Klitsie

11/17/2020, 4:46 PM
I mean if you want to adjust behavior of the child in many ways, you might just want to extract some basic behavior in a child and simply pass on more children to the child, I think this was explained in some interesting video
lemme check it

https://www.youtube.com/watch?v=SMOhl9RK0BA

here we go, around 8:50
z

Zach Klippenstein (he/him) [MOD]

11/17/2020, 4:48 PM
To group them, like Adam suggested:
Copy code
class YourComplicatedState {
  private val _foo: MutableState<Foo> = mutableStateOf(…)
  private val _bar: MutableState<Bar> = mutableStateOf(…)
  val foo: State<Foo> = _foo
  val bar: State<Bar> = _bar

  fun doSomeAction() {
    _foo.value = …
    _bar.value = …
  }
}

@Composable
fun Parent() {
    var state by remember { YourComplicatedState() }
    Child(state)
}

@Composable
fun Child(state: YourComplicatedState) {
    Button(onClick = { state.doSomeAction() })
}
☝️ 1
t

Tony Mykhaylovsky

11/17/2020, 4:48 PM
That's great - thank you
2 Views