Partial shared States across different Stores

Hi, I please need some help with sharing partial states with different views:
I have a MainView displaying a HomeView which can present a Modal View for changing Settings.
My Idea was to have a shared state to contain things like a configurable hostname that will be used in MainView and changed by SettingsView. HomeView needs to have the property to present the Modal and SettingsView needs to change that property in order to hide itself.

enum Main {
    struct State: Equatable {
        var sharedState: Shared.State
        var homeState: Home.State
        var settingsState: Settings.State
    }
}

enum Shared {
    struct State: Equatable {
        var hostname: String?
    }
}

enum Home {
    struct State: Equatable {
        var showsSettingsModal = false
    }
}

enum Settings {
    struct State: Equatable {
        var showsSettingsModal = false
        var hostname: String?
    }
}

I did not want to have all properties in MainState to not pollute it, but I don't know how to access Shared.State from e.g. Settings.State as this currently results in having two Shared.States.
Also I would not want to derive Settings completely from Main.
The examples don't really show how to deal with partial sharing. Any recommendations please?

We definitely need to beef up the shared state example in our case studies to show more complex scenarios.

I recently replied to a thread that explained two additional techniques for sharing state that you might find helpful:

Thanks, could you give a hint how to send actions then over the different stores?
The idea is a Home View which can connect to the API and a Settings Modal setting e.g. hostname in shared state.

// HomeView
HomeView<HomeFeatureState, Home.Action, Home.Environment> {
    WithViewStore(self.store) { viewStore in 
        VStack { ... }
        .sheet(isPresented: viewStore.binding( get: { $0.showSettingsModal }, send: Home.Action.toggleSettingsModal)) {
                SettingsView(store:  ...)
            }
    }
}

@dynamicMemberLookup
struct HomeFeatureState: Equatable {
    var home: Home.State
    var shared: Shared.State
    var api: Api.State

    subscript...
}
// HomeStore
enum Home {
    enum Action {
        case connect
    }
}
// ApiStore
enum Api {
    enum Action {
        case connectApi(URL)
    }
}

And I want to call the connectAPI action from HomeView. I tried with:

// HomeView
HomeView<HomeFeatureState, HomeFeatureAction, Home.Environment>

enum HomeFeatureAction {
    case home(Home.Action)
    case api(Api.Action)
}

Which results in the compiler not doing anything and viewStore.binding throwing errors.

For anybody looking for a solution to share properties across multiple Stores: I created a gist for an example I created.

In short it works like this:

  • Main.State contains all your states and takes care of pulling data from those back to itself.
  • Shared.State contains the properties you want to share across.
  • The Home.HomeFeature and Settings.SettingsFeature combine those two States
  • The Store extension eases scoping your State to your views
  • dynamicMemberLookup resolves your properties

Maybe somebody has an idea how to have the mutation for Shared.State.sharedProperty in only one central place instead of two.

1 Like