Last active
August 8, 2023 17:09
-
-
Save taskcruncher/a482883eab0f8cf07b2f7d86bbd48004 to your computer and use it in GitHub Desktop.
BaseStateExampleWithGenericAppState.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//How to use BaseState struct to share state between views in TCA architecture. | |
// https://forums.swift.org/t/best-practice-for-sharing-data-between-many-features/37696/4 | |
//This is a proof-of-concept only; it simply is an attempt to model how to get and set global shared state among different views in a TCA-style app. | |
import SwiftUI | |
import ComposableArchitecture | |
@dynamicMemberLookup | |
struct TCABaseState<State: Equatable>: Equatable{ | |
var sharedState: SharedState | |
var state: State | |
init(sharedState: SharedState, state: State){ | |
self.sharedState = sharedState | |
self.state = state | |
} | |
//https://www.swiftbysundell.com/tips/combining-dynamic-member-lookup-with-key-paths/ | |
subscript<T>(dynamicMember keyPath: WritableKeyPath<State, T>) -> T { | |
get { state[keyPath: keyPath] } | |
set { state[keyPath: keyPath] = newValue } | |
} | |
} | |
struct SharedState: Equatable { | |
var activeInternetConnection = true | |
var isUserLoggedIn = false | |
} | |
struct TCAAppState: Equatable { | |
var sharedState = SharedState() | |
var person = Person() | |
var personState: TCABaseState<Person> {get { TCABaseState(sharedState: sharedState, state: person)} set{self.person = newValue.state | |
self.sharedState = newValue.sharedState | |
}} | |
var dog = Dog() | |
var dogState: TCABaseState<Dog> {get { TCABaseState(sharedState: sharedState, state: dog)} set{self.dog = newValue.state | |
self.sharedState = newValue.sharedState | |
}} | |
} | |
struct Person: Equatable { | |
var name = "Bill" | |
} | |
struct Dog: Equatable{ | |
var name = "Fido" | |
} | |
enum DogAction { | |
case changeName | |
} | |
enum PersonAction { | |
case changeName | |
case toggleInternetState | |
} | |
enum TCAAppAction { | |
case person(PersonAction) | |
case dog(DogAction) | |
} | |
func displayInternetConnectionStatus(_ bool: Bool) -> some View { | |
switch bool { | |
case true: return Text("internet is connected") | |
default: return Text("No internet") | |
} | |
} | |
struct PersonView: View { | |
let store: Store<TCABaseState<Person>, PersonAction> | |
var body: some View { | |
WithViewStore(store) {viewStore in | |
Text("Hello \(viewStore.name)") | |
Button("Change name"){viewStore.send(.changeName)} | |
Button("ToggleInternetState"){viewStore.send(.toggleInternetState)} | |
displayInternetConnectionStatus(viewStore.sharedState.activeInternetConnection) | |
} | |
} | |
} | |
struct DogView: View { | |
let store: Store<TCABaseState<Dog>, DogAction> | |
var body: some View { | |
WithViewStore(store) {viewStore in | |
Text("Hello \(viewStore.name)") | |
displayInternetConnectionStatus(viewStore.sharedState.activeInternetConnection == true) | |
} | |
} | |
} | |
struct RootView: View { | |
let store: Store<TCAAppState, TCAAppAction> | |
var body: some View { | |
PersonView(store: store.scope(state: {$0.personState}, action: {TCAAppAction.person($0)})) | |
.padding() | |
DogView(store: store.scope(state: {$0.dogState}, action: {TCAAppAction.dog($0)})) | |
.padding() | |
} | |
} | |
//struct ContentView_Previews: PreviewProvider { | |
// static var previews: some View { | |
// PersonView() | |
// } | |
//} | |
var dogReducer = Reducer<TCABaseState<Dog>, DogAction, Void> {state, action, _ in | |
switch action { | |
case .changeName: state.state.name = "Rover" | |
state.sharedState.activeInternetConnection = true | |
} | |
return .none} | |
var personReducer = Reducer<TCABaseState<Person>, PersonAction, Void> {state, action, _ in | |
switch action { | |
case .changeName: state.state.name = "Quinton" | |
state.sharedState.activeInternetConnection = true | |
case .toggleInternetState: state.sharedState.activeInternetConnection.toggle() | |
} | |
return .none} | |
var appReducer = Reducer.combine(dogReducer.pullback(state: \TCAAppState.dogState, action: /TCAAppAction.dog, environment: {}), personReducer.pullback(state: \TCAAppState.personState, action: /TCAAppAction.person, environment: {})) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment