Simplified Environment management with ComposableEnvironment #554
                  
                    
                      tgrapperon
                    
                  
                
                  started this conversation in
                Show and tell
              
            Replies: 0 comments
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
        
    
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello everyone!
I've just open-sourced
ComposableEnvironment.I'm working on a consequent project with TCA and the bookkeeping of dependencies has started to be quite annoying. When I'm adding an unplanned dependency to a leaf feature, I'm forced to update all the initializers and environments up to the root Environment. In some areas, that's up to 10 environments to update. I've written this simple library a few days ago and it simplified greatly my dependencies management in the app (I didn't update all the environments in my app yet, but it's not mandatory for the library to work). It's working fine enough to open-source it.
I took inspiration from
SwiftUIand the way they manage their environment. You can find a little more info in the (ReadMe)[https://github.com/tgrapperon/swift-composable-environment/blob/main/README.md]. In a few words, you declare dependencies like you declareEnvironmentValue's in SwiftUI, with adefaultValueand a computed property in aComposableDepenciesstruct. You can then use this dependency like you would use an@Environmentvalue in a SwiftUIView, with a keyPath. You can also declare derived environments in your environment and their dependencies will automatically in sync dependencies with their parent's one.You don't have to bind explicitly the child environment in its parent. You can update a dependency with a
with(keypath, value)chaining API and these changes will only affect the environments downstream (like in SwiftUI)This works well with testing and with SwiftUI previews., as you can quickly construct an environment with a specific configuration with the chaining API.
Here is an example of the API in action, declaring and sharing a
mainQueuedependency:The only noticeable difference with canonical TCA is that your environment needs to be a class (a subclass of
ComposableEnvironmentto be more specific). This is forced by the obligation to go up to the hosting instance in the property wrappers (it works only for reference types). Otherwise, one would be forced to use reflection at the expense of performance (and even then, I'm not even sure it can work at the end). As a positive side effect, child environment instances are cached, and dependencies are shared. There should be no impact on performances.Please note that, like in SwiftUI, dependencies are passing through environments, even if they are not explicitly declared by an inner link of the chain. That is, in the chain
root -> child1 -> child2of environments, you can declare atimedependency inrootand retrieve it inchild2, even ifchild1doesn't declare this dependency. In other words, you don't have to stuff your environments with dependencies they only keep to pass to child environments. This is one of the main key points of the library.To sum up, your environment needs to be a subclass of
ComposableEnvironment(no additional constraint), you declare dependencies in them with the@Dependencyproperty wrapper and child environments with the@DerivedEnvironmentproperty wrapper. You register your dependencies à la SwiftUI, withDependencyKeyandComposableDependencies, and you can update environment's dependencies with thewith(keyPath, value)chaining API. As a bonus, you can directly use the derived environment'sKeyPathwhen pulling back reducers. The library can instantiate childComposableEnvironment's by itself, but it will also use any instance you provide to the@DerivedEnvironmentwrapper. It also preserves undecorated properties in yourComposableEnvironmentsubclasses.Please let me know if you have ideas for improvement!
Beta Was this translation helpful? Give feedback.
All reactions