# @WrappedStore property wrapper to get rid of boilerplate

**URL:** <https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058>\
**Category:** Swift Composable Architecture\
**Tags:** propertywrapper\
**Created:** [May 31, 2021, 1:32am UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058 "2021-05-31T01:32:46Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![nikitamounier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nikitamounier/32/24825_2.png) [@nikitamounier](https://forums.swift.org/u/nikitamounier)\
**Post date:** [May 31, 2021, 1:32am UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/1 "2021-05-31T01:32:47Z")

</div>

Ever since I started using TCA, `WithViewStore` always felt weird to me – it felt like I was infecting store logic into my view `body` properties, which I always like to keep clean and pure (`viewStore.binding` gives me the same sensation, but there's no getting rid of that 😅). Paired with its weird behaviour with certain types of views like `GeometryReader`, I've diverted from using it, and have instead stuck to using a `store` property and an `@ObservedObject var viewStore`. This has been reinforced by the fact that [isowords](https://github.com/pointfreeco/isowords) also prefers to use this method over `WithViewStore`.

However, the two properties + custom initialisation, although nothing which can't be solved with a Sourcery template, feels cumbersome and repetitive. That's why I created the simple `@WrappedStore` property wrapper to get rid of this boilerplate. It looks like this:

```swift
@propertyWrapper
public struct WrappedStore<State, Action>: DynamicProperty {
    public let wrappedValue: Store<State, Action>
    
    @ObservedObject public var projectedValue: ViewStore<State, Action>
    
    public init(wrappedValue store: Store<State, Action>) where State: Equatable {
        self.init(wrappedValue: store, removeDuplicates: ==)
    }
    
    public init(wrappedValue store: Store<State, Action>, removeDuplicates isDuplicate: @escaping (State, State) -> Bool) {
        self.wrappedValue = store
        self.projectedValue = ViewStore(store, removeDuplicates: isDuplicate)
    }
}

```

Now, views can look like this:

```swift
struct ContentView: View {
    @WrappedStore var store: Store<AppState, AppAction>
    
    var body: some View {
        ChildView(store: store.scope(state: \.childState, action: AppAction.childAction))
    }
}

struct ChildView: View {
    @WrappedStore var store: Store<ChildState, ChildAction>
    
    var body: some View {
        VStack {
            TextField("String", text: $store.binding(get: \.text, send: ChildAction.setText))
            Button("Increment Counter: \($store.counterState)") {
                $store.send(.increment)
            }
        }
    }
}

```

I wish the Store could be the projectedValue, and ViewStore the wrappedValue (since it's used more), but then I wouldn't be able to have the `store:` initialiser – I'm open to solutions though. And of course, the name WrappedStore is open to bikeshedding.

Would love to hear what @stephencelis and @mbrandonw think about this!

---

<div class="post-metadata">

**Author:** ![Kevin\_Lundberg](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kevin_lundberg/32/353_2.png) [@Kevin\_Lundberg](https://forums.swift.org/u/Kevin_Lundberg)\
**Post date:** [May 31, 2021, 2:22am UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/2 "2021-05-31T02:22:46Z")

</div>

This is really cool!

One thing I can think of that could improve this is to allow for the property wrapper to accept a keypath or closure parameter that lets you scope on a specific piece of child state that's intended to be what the viewstore listens to. Otherwise any state change (even changes that don't concern the view in question) could cause a re-render which might introduce performance/ui bugs.

If I could possibly do something like this, that would be a great addition to this technique:

```swift
struct MyState: Equatable {
  ...
  struct ViewState {
    ...
  }
  var view: ViewState {
    ...
  }
}

struct MyView: View {
  @WrappedStore(viewState: \.view) var store: Store<MyState, MyAction>
  
  var body: some View {
    /* $store is of type ViewStore<MyState.ViewState, MyAction>
       and only ViewState changes are checked for view updates to this view */
  }
}

```

The keypath parameter could be optional and default to `\.self` if you don't need that sort of precision in what state you listen to, perhaps.

---

<div class="post-metadata">

**Author:** ![mbrandonw](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mbrandonw/32/349_2.png) [@mbrandonw](https://forums.swift.org/u/mbrandonw)\
**Post date:** [May 31, 2021, 3:04am UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/3 "2021-05-31T03:04:06Z")

</div>

> [@nikitamounier](#):
>
> This has been reinforced by the fact that [isowords](https://github.com/pointfreeco/isowords) also prefers to use this method over `WithViewStore` .

FWIW it's not that we have a preference. We have plenty of usages of `WithViewStore` in the code base. We usually opt for the `@ObservedObject` when the view is complicated enough that autocomplete breaks down. There's something about SwiftUI views whose content is expressed as a closure with an argument that stresses the compiler. I experience this with `GeometryReader` and `ScrollViewReader` where the `proxy` argument often doesn't have any autocomplete. There's a chance that Xcode 12.5 has improved this.

Your `@WrappedStore` property wrapper is interesting, but ultimately it blurs the line between `Store` and `ViewStore` in a way that is not appropriate for TCA. One of the primary purposes of the `ViewStore` is to chisel away the state to the bare essentials a view needs to do its job. This can be important for the performance of some views. We have lots of examples of this in isowords and lots of episodes on this topic (and more coming in a few weeks).

With the way `@WrappedStore` is designed now you would always observe all state in the store every time you use it in a view, even if you only need a small piece of the state to actually display the view.

Stephen and I played with properties quite a bit to try to meld the concepts of `Store` and `ViewStore` in a way that preserved the utility of view stores and the ergonomics of the dedicated `ViewStore` type, but we could never figure it out. I believe that property wrappers are missing a few features that would make it possible. Essentially, we'd love if @Kevin_Lundberg's proposed syntax could work, but we're not sure how.

---

<div class="post-metadata">

**Author:** ![nikitamounier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nikitamounier/32/24825_2.png) [@nikitamounier](https://forums.swift.org/u/nikitamounier)\
**Post date:** [May 31, 2021, 1:15pm UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/4 "2021-05-31T13:15:22Z")

</div>

> [@mbrandonw](#):
>
> With the way `@WrappedStore` is designed now you would always observe all state in the store every time you use it in a view

AFAIU, `@WrappedStore` behaves the exact same way as using a `store` property and an `@ObservedObject var viewStore`.  
`DynamicProperty` works in the same way as `View` in that it only triggers a reload when either a value type property is mutated, or it receives an `objectWillChange` signal – there's no way for it to know that a reference type was mutated otherwise.

I tested the view reload count using both methods – you can find the [gist with the code here](https://gist.github.com/nikitamounier/cbea8cde0193285ad32939837edac3da).

 ![Simulator Screen Shot - iPhone 12 - 2021-05-31 at 12.57.35](https://global.discourse-cdn.com/swift/original/3X/6/3/6319b864c90db6720e43ec204887ca6d5d86dcc9.png)

This is when using `@WrappedStore`:

 ![Screenshot 2021-05-31 at 12.58.46](https://global.discourse-cdn.com/swift/original/3X/7/f/7f92646577f04baee677c597ae372e3cb41521f4.jpeg)

And this is when using the `store` property / `@ObservedObject var viewStore`:

 ![Screenshot 2021-05-31 at 13.04.30](https://global.discourse-cdn.com/swift/original/3X/c/c/cc81f1a77178a44f126ba436d2e6cf1fbede456d.jpeg)

So, `@WrappedStore` is equivalent when you're just scoping the store down each view.

I agree, though, that right now we can't observe only a certain `ViewState` when using `@WrappedStore`, although I'm working on it right now.

Firstly, it would have to be a new property wrapper, since it introduces a third generic type for the new local state, and I wouldn't want to force the user of `@WrappedStore` to specify a third generic type which would be equivalent to the first. Let's call this property wrapper `@WrappedStoreLocal`.

The main issue is that is needs to phases of initialisation: one where the user passes in the closure/keypath which would convert parent state into the local state, and another where the caller passes in the store. This is simply not possible right now with property wrappers – [here's a gist](https://gist.github.com/nikitamounier/9ebfbbb2ff6a1362d889156472cd47d0) with my best try at an implementation of `@WrappedStoreLocal`.

I'd love to hear any solutions for this!

---

<div class="post-metadata">

**Author:** ![mbrandonw](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mbrandonw/32/349_2.png) [@mbrandonw](https://forums.swift.org/u/mbrandonw)\
**Post date:** [May 31, 2021, 2:54pm UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/5 "2021-05-31T14:54:53Z")

</div>

> [@nikitamounier](#):
>
> So, `@WrappedStore` is equivalent when you're just scoping the store down each view.

Yeah this is true. If you are observing the full state of the store, then `@WrappedStore` is equivalent to `@ObservedObject var viewStore`. But we feel that observing all of the state in a store should be an infrequent thing. The only time it's probably appropriate is when you are a leaf view node or close to a leaf.

Now having said that, if your application is humming along fine without being super prescriptive with what state is being observed in the view store, and you are not seeing performance problems then it is seems completely fine to use the `@WrappedStore` property wrapper. It's just not something we will bake into the library unless we can figure out how to recover the full functionality of `ViewStore` in it.

---

<div class="post-metadata">

**Author:** ![nikitamounier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nikitamounier/32/24825_2.png) [@nikitamounier](https://forums.swift.org/u/nikitamounier)\
**Post date:** [May 31, 2021, 3:55pm UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/6 "2021-05-31T15:55:01Z")

</div>

I completely agree – making a custom `ViewState` struct for the view should be the default for performance. I guess I'll only use `@WrappedStore` when I'm just doing a simple `store.scope(state:action)`, and then revert back to `@ObservedObject var viewStore` when I need a custom `ViewState`.

I'll keep on working on `@WrappedStoreLocal` though! Ultimately, I want it to look like this:

```swift
struct MyView: View {
    struct ViewState: Equatable {
        // ...
        init(state: AppState) { /* ... */ }
    }
    
    @WrappedStoreLocal(viewState: ViewState.init) var store: Store<AppState, AppAction>

    var body: some View {
        // ...
    }
}

struct ParentView: View {
    @WrappedStore var store: Store<AppState, AppAction>

    var body: some View {
        MyView(store: store)
    }
}
```

---

<div class="post-metadata">

**Author:** ![mbrandonw](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mbrandonw/32/349_2.png) [@mbrandonw](https://forums.swift.org/u/mbrandonw)\
**Post date:** [May 31, 2021, 3:57pm UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/7 "2021-05-31T15:57:47Z")

</div>

> [@nikitamounier](#):
>
> I'll keep on working on `@WrappedStoreLocal` though! Ultimately, I want it to look like this:

Please let us know what you find! That theoretical syntax is about what we want too. If we can achieve it we would even consider renaming it to something like `@ViewStore(state:action:) var store: Store<...>`😬

---

<div class="post-metadata">

**Author:** ![mycroftcanner](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mycroftcanner/32/12683_2.png) [@mycroftcanner](https://forums.swift.org/u/mycroftcanner)\
**Post date:** [May 31, 2021, 6:30pm UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/8 "2021-05-31T18:30:20Z")

</div>

```swift
@propertyWrapper
public struct ViewStore<State, Action, LocalState>: DynamicProperty {
  public let wrappedValue: Store<State, Action>
  
  @ObservedObject public var projectedValue: ViewStore<LocalState, Action>
    
  public init(
    wrappedValue store: Store<State, Action>,
    state toLocalState: @escaping (State) -> LocalState
  ) where State: Equatable, LocalState: Equatable {
    self.init(wrappedValue: store, state: toLocalState, removeDuplicates: ==)
  }
  
  public init(
    wrappedValue store: Store<State, Action>,
    state toLocalState: @escaping (State) -> LocalState,
    removeDuplicates isDuplicate: @escaping (LocalState, LocalState) -> Bool
  ) {
    self.wrappedValue = store
    self.projectedValue = ViewStore(store.scope(state: toLocalState), removeDuplicates: isDuplicate)
  }
}

```

Sadly, this:

```swift
@ViewStore(state: ViewState.init) var store: Store<AppState, AppAction>

```

doesn't work yet:

> Missing argument for parameter 'wrappedValue' in call

There is a pitch to [Allow Property Wrappers with Multiple Arguments to Defer Initialization when wrappedValue is not Specified](https://forums.swift.org/t/allow-property-wrappers-with-multiple-arguments-to-defer-initialization-when-wrappedvalue-is-not-specified/38319).

---

<div class="post-metadata">

**Author:** ![nikitamounier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nikitamounier/32/24825_2.png) [@nikitamounier](https://forums.swift.org/u/nikitamounier)\
**Post date:** [May 31, 2021, 9:42pm UTC](https://forums.swift.org/t/wrappedstore-property-wrapper-to-get-rid-of-boilerplate/49058/9 "2021-05-31T21:42:20Z")

</div>

> [@mycroftcanner](#):
>
> There is a pitch to [Allow Property Wrappers with Multiple Arguments to Defer Initialization when wrappedValue is not Specified](https://forums.swift.org/t/allow-property-wrappers-with-multiple-arguments-to-defer-initialization-when-wrappedvalue-is-not-specified/38319).

Yep, that's exactly what I was looking for. Seems like many people want this, and according to @hborla shouldn't be incredibly difficult to implement (then again, I'm not a language/compiler dev, so what do I know 😅). I made a small post on that thread to reignite the discussion, thanks a lot!
