I'd like to add support for the nested properties in Produced values, current implementation use
@dynamicMemberLookup, which does not support nested properties yet, and I have 2.5 solutions:
Zero (not a real one, I mean ๐
)
Use
viewStore.property.map(\.nestedProperty).skipRepeats()
which is okay, but not the most convenient stuff.
First
Add another method to the ViewStore
type to support default KeyPath stuff:
viewStore.producer(for: \.KeyPath<State, Value>) -> Produced<Value>
That extremely easy and fits ReactiveSwift, but I'm not sure if it fits ComposableArchitecture.
Maybe it worth mentioning in readme or smth if approved.
I use it locally now btw.
Second
Use Produced
type as a dynamicMemberLookup container and do not return a producer implicitly, but return mapped itself.
/// A producer of store state.
@dynamicMemberLookup
public struct Produced<Value> { // <- have to drop `SignalProducerConvertible` protocol
private let _producer: Effect<Value, Never> // <- private stuff
init(by upstream: Effect<Value, Never>) {
self._producer = upstream
}
/// Returns the resulting producer of a given key path.
public subscript<LocalValue>(
dynamicMember keyPath: KeyPath<Value, LocalValue>
) -> Produced<LocalValue> {
Produced<LocalValue>(by: _producer.map(keyPath)) // <- here is a change
}
}
extension Produced {
public var producer: Effect<Value, Never> { _producer } // <- Logic inconsistency {li}
}
extension Produced where Value: Equatable {
public var producer: Effect<Value, Never> { _producer.skipRepeats() } // <- Logic inconsistency {li}
}
Usage:
viewStore.property.nestedProperty.producer
That will lead to more consistent API, but the implementation will be major so that users won't be able to subscribe to any property without explicitly calling the producer
anymore. Also, there is a little logic inconsistency at {li}
marks due to Equatable conformance, that should be tested and anyways it may suffer from type erasure stuff.