Thread
#compose
    Noé Casas

    Noé Casas

    1 year ago
    Is it Ok to use non-local state from a Composable function? An example would be a Composable that shows a Text with a String taken from a 
    MutableState
     stored as a member of an object retrieved through an Ambient, like this:
    data class ServiceX (
       val whateverString: MutableState<String>("meow")
    )
    
    
    @Composable
    fun Whatever() {
       val serviceX = AmbientServiceX.current
       Text(serviceX.whateverString)
    }
    Will the Composable function repaint when 
    whateverString
     changes? Are there any problems with this?
    jim

    jim

    1 year ago
    If someone is using ambients, I am 99% sure they are abusing them. Think of ambients like globals. Sometimes they are useful/necessary, but you should feel guilty every time you use them.
    Specifically, Ambients (like globals) create implicit dependencies which makes it hard to track the flow of information through larger codebases.
    Noé Casas

    Noé Casas

    1 year ago
    In this case the ambient is to distribute the instance of a service that keeps as a member variable the user that is logged in, together with other info, similar to this: https://foso.github.io/Jetpack-Compose-Playground/general/ambient/#how-to-use-a-value-of-an-ambient . Is this use of the ambient fair? Would it work properly with the Composable?
    Adam Powell

    Adam Powell

    1 year ago
    It will work from a mechanical perspective, and yes, your UI will invalidate and recompose as expected when that snapshot state object changes. But as Jim pointed out, there are other reasons you might not want to structure your code that way for understandability and maintainability.
    In addition to ambients being implicit dependencies that add complications to both usage and testability, you probably don't want to pass raw MutableState objects to a constructor. That implies a kind of complicated ownership model for that state; what is it shared with? Who has access to mutate it and under what circumstances?
    Noé Casas

    Noé Casas

    1 year ago
    The state contains information about the logged user, including permissions they have, so any Composable that needs permission checking is a candidate for checking it. Also, top level Composables check if the state is null to show a login form or the normal UI. The state is only mutated when logging in, logging out or async refreshing of the user info.
    Adam Powell

    Adam Powell

    1 year ago
    generally you would want to write
    ServiceX
    as something more like:
    class ServiceX(whateverString: String) {
      var whateverString by mutableStateOf(whateverString)
        private set // optional, but often useful!
      // ...
    }
    with the key distinction being keeping the
    MutableState
    object as an implementation detail. Then all of the usual OO patterns apply, the only difference is that changes to ServiceX's internal state are observable.
    Noé Casas

    Noé Casas

    1 year ago
    I see. With that structure I understand that modifications to
    whateverString
    by means of a public function of
    ServiceX
    would trigger the repaint of Composables that use
    whateverString
    (e.g.
    Text(serviceX.whateverString)
    ), right?
    Adam Powell

    Adam Powell

    1 year ago
    yes. Observation is transitive across the call stack; even if the actual snapshot state object is many objects or function calls away, compose still knows it was accessed.
    Noé Casas

    Noé Casas

    1 year ago
    Perfect, thanks a lot!