Best way for @Dependency to send action to reducer #1437
-
What is the best way to let a dependency notify the reducer that its contents changed? One setup I'm using now is to have a private private let eventsSubject = PassthroughSubject<Event, Never>()
public let eventsEffect: Effect<Event, Never>
init() {
self.eventsEffect = Effect(eventsSubject)
}
// ...
// In reducer
case .launched:
return myDependency.eventsEffect.map(Action.receivedEvent)
case .receivedEvent(Event):
// do something So now for the questions: Is this a good idea or is there a better way? And especially:
Would it be completely crazy to put some common state that often changes and is used by every single leaf view, in the Just FYI, one of the dependencies I need to subscribe to is CoreData, others are my own audio players and similar. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 13 replies
-
Since the "concurrency" update, the easiest way to handle this is indeed an case .observeDependency:
return .run { send in
for await value in myDependency.asyncValues {
await send(.receivedEvent(value))
}
}
case let .receivedEvent(value):
// Do whatever you need to do each time the value changes.
state.count = value.count
return .none Now in the view, you exploit the fact that the Text("Hello!")
.task {
await viewStore.send(.observeDependency).finish()
} So this Subscribing in this way in a hundred of views is very likely a bad idea, as it will generate a considerable traffic of actions for the store. You should probably find a way to pass the udpated value along the states while scoping. It doesn't need to be monolithic, and you can maybe have a few subscriptions that handle a few runs of scoped states if it's more convenient in your case. We would maybe be able to provide more precise feedback with a more explicit use-case. What are your 100 views? rows in a list? |
Beta Was this translation helpful? Give feedback.
-
So I don't have either compiler directives, As to AsyncSequence, I do have a publisher in one of the dependencies, but I'd rather make it an AsyncSequence directly. For the others, I haven't added any subscription stuff yet. Haven't found any basic examples of adding AsyncSequence, do you know any? |
Beta Was this translation helpful? Give feedback.
-
Actually it's more like
So maybe it's all these geometry readers that confuse SwiftUI. |
Beta Was this translation helpful? Give feedback.
Since the "concurrency" update, the easiest way to handle this is indeed an
AsyncSequence
of some sort. The most convenient approach involves 2 actions: one that you can call.observeDependency
(or.task
) that you use to trigger and handle the subscription's lifecycle, and one that you can call.receivedEvent(Value)
that you use to perform the changes when appropriate.In you reducer, you implement:
Now in th…