Skip to content

Instantly share code, notes, and snippets.

@taskcruncher
Last active August 8, 2023 17:09
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taskcruncher/a482883eab0f8cf07b2f7d86bbd48004 to your computer and use it in GitHub Desktop.
Save taskcruncher/a482883eab0f8cf07b2f7d86bbd48004 to your computer and use it in GitHub Desktop.
BaseStateExampleWithGenericAppState.swift
//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