Hello Swift and TCA Community,
I am working on a SwiftUI project utilizing TCA and facing a challenge with maintaining persistent state in child views when switching tabs using SwitchStore
.
Issue Description: In my application, I have a tabbed interface where each tab is represented by a separate view and state in TCA. I am using SwitchStore
to switch between these tabs. I have an .onAppear()
, which gets ran once, that updates the state of my child ReminderPreferencesFeature
state. However, every time I switch tabs, the state of the child views seems to be reinitialized, losing any stateful information or changes made in those child views.
Here is a simplified version of my code structure:
Store:
import Foundation
import ComposableArchitecture
// Model
struct PreferenceTab: Identifiable, Hashable {
let id: Int
var imgString: String
let name: String
var isSelected: Bool
}
@Reducer
struct PreferencesFeature {
enum State: Equatable {
case reminderTab(ReminderPreferencesFeature.State)
case sharingTab(SharingPreferencesFeature.State)
case sortingTab(SortingPreferencesFeature.State)
// Default selected the first tab
init() { self = .reminderTab(ReminderPreferencesFeature.State()) }
}
enum Action: Equatable {
case selectTab(Int)
case dismissSheet
case reminderTab(ReminderPreferencesFeature.Action)
case sharingTab(SharingPreferencesFeature.Action)
case sortingTab(SortingPreferencesFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: \.reminderTab, action: \.reminderTab) {
ReminderPreferencesFeature()._printChanges()
}
Reduce { state, action in
switch action {
case .selectTab(let id):
switch id {
case 0:
state = .reminderTab(ReminderPreferencesFeature.State())
case 1:
state = .sharingTab(SharingPreferencesFeature.State())
case 2:
state = .sortingTab(SortingPreferencesFeature.State())
default:
break
}
return .none
// On dismissal, reset default tab back to reminder
case .dismissSheet:
state = .reminderTab(ReminderPreferencesFeature.State())
return .none
case .reminderTab:
return .none
case .sharingTab:
return .none
case .sortingTab:
return .none
}
}
.ifCaseLet(\.reminderTab, action: \.reminderTab) {
ReminderPreferencesFeature()
}
.ifCaseLet(\.sharingTab, action: \.sharingTab) {
SharingPreferencesFeature()
}
.ifCaseLet(\.sortingTab, action: \.sortingTab) {
SortingPreferencesFeature()
}
}
}
SwitchStore:
SwitchStore(self.store) { state in
switch state {
case .reminderTab:
// Present reminders
CaseLet(\PreferencesFeature.State.reminderTab, action: PreferencesFeature.Action.reminderTab) { store in
ReminderPreferencesView(store: store, event: event, recipient: recipient)
}
case .sharingTab:
// Present sharing preferences
CaseLet(\PreferencesFeature.State.sharingTab, action: PreferencesFeature.Action.sharingTab) { store in
SharingPreferencesView(store: store)
}
case .sortingTab:
// Present sorting preferences
CaseLet(\PreferencesFeature.State.sortingTab, action: PreferencesFeature.Action.sortingTab) { store in
SortingPreferencesView(store: store)
}
}
}
I am looking for guidance or best practices on how to maintain the state of each child view when switching tabs with SwitchStore
in TCA. Any suggestions or insights on how to properly structure the state and actions to achieve this would be greatly appreciated.
Thank you in advance for your help!