Redux-like state container in SwiftUI. Derived stores.
Tags: swift, ios, mobile, programming
Published: 2023-02-18 11:46:23

Another way of [composition](https://dev.to/sergeyleschev/redux-like-state-container-in-swiftui-reducer-composition-3j0m) that should simplify our architecture is derived stores. I don’t want to expose the whole app state to every view or update views on not related state updates.

```swift
import SwiftUI

struct RootView: View {
    @EnvironmentObject var store: Store<AppState, AppAction>

    var body: some View {
        TabView {
            NavigationView {
                SummaryContainerView()
                    .navigationBarTitle("today")
                    .environmentObject(
                        store.derived(
                            deriveState: \.summary,
                            deriveAction: AppAction.summary
                        )
                )
            }.tabItem {
                Image(systemName: "heart.fill")
                    .imageScale(.large)
                Text("today")
            }

            NavigationView {
                TrendsContainerView()
                    .navigationBarTitle("trends")
                    .environmentObject(
                        store.derived(
                            deriveState: \.trends,
                            deriveAction: AppAction.trends
                        )
                )
            }.tabItem {
                Image(systemName: "chevron.up.circle.fill")
                    .imageScale(.large)
                Text("trends")
            }
        }
    }
}
```

Every tab of my app gets its part of the state via the derived store. We still use the global store to handle all the state mutation. Derived store works as a pipeline that allows us to transform the state from the global store and redirect actions to the global store. Let’s take a look at how we can implement the `derived` method for our `Store` class.

```swift
func derived<DerivedState: Equatable, ExtractedAction>(
    deriveState: @escaping (State) -> DerivedState,
    embedAction: @escaping (ExtractedAction) -> Action
) -> Store<DerivedState, ExtractedAction> {
    let store = Store<DerivedState, ExtractedAction>(
        initialState: deriveState(state),
        reducer: Reducer { _, action, _ in
            self.send(embedAction(action))
            return Empty().eraseToAnyPublisher()
        },
        environment: ()
    )
    $state
        .map(deriveState)
        .removeDuplicates()
        .receive(on: DispatchQueue.main)
        .assign(to: &store.$state)
    return store
}
```

---

**Redux** provides a single source of truth, which eliminates tons of bugs produced by multiple states across the app. Best practices. Normalization and composition keep our app state simple and maintainable.

- [State normalization](https://dev.to/sergeyleschev/redux-like-state-container-in-swiftui-state-normalization-108o).
- [State composition](https://dev.to/sergeyleschev/redux-like-state-container-in-swiftui-state-composition-57e5).
- [Reducer composition](https://dev.to/sergeyleschev/redux-like-state-container-in-swiftui-reducer-composition-3j0m).
- [Derived stores](https://dev.to/sergeyleschev/redux-like-state-container-in-swiftui-derived-stores-2d62).

---

**Contacts**
I have a clear focus on time-to-market and don't prioritize technical debt. And I took part in the Pre-Sale/RFX activity as a System Architect, assessment efforts for Mobile (iOS-Swift, Android-Kotlin), Frontend (React-TypeScript) and Backend (NodeJS-.NET-PHP-Kafka-SQL-NoSQL). And I also formed the work of Pre-Sale as a CTO from Opportunity to Proposal via knowledge transfer to Successful Delivery.

🛩️ #startups #management #cto #swift #typescript #database
📧 Email: sergey.leschev@gmail.com
👋 LinkedIn: https://linkedin.com/in/sergeyleschev/
👋 LeetCode: https://leetcode.com/sergeyleschev/
👋 Twitter: https://twitter.com/sergeyleschev
👋 Github: https://github.com/sergeyleschev
🌎 Website: https://sergeyleschev.github.io
🌎 Reddit: https://reddit.com/user/sergeyleschev
🌎 Quora: https://quora.com/sergey-leschev
🌎 Medium: https://medium.com/@sergeyleschev