Shared state

Hi Guys!

I have a question, what is the best way to share state across main AppState and the children:

The scenario:

When the property counter will change in the Screen1State then I would like to have this refreshed "counter" property in the Screen2State and vice versa.

Many thanks for any advice!!!!

I don't know if its the best way but I'm doing like this:

struct AppState {
  init(counterState: CounterState, 
       screen1State: Screen1State, 
       screen2State: Screen2State) {
    self.counterState = counterState
    self._screen1State = screen1State
    self._screen2State = screen2State
  }

  var counterState: CounterState

  private(set) var _screen1State: Screen1State
  var screen1State: Screen1State {
    get {
      var state = _screen1State
      state.counterState = counterState
      return state
    }
    set {
      _screen1State = newValue
      counterState = newValue.counterState
    }
  }

  private(set) var _screen2State: Screen2State
  var screen2State: Screen2State {
    get {
      var state = _screen2State
      state.counterState = counterState
      return state
    }
    set {
      _screen2State = newValue
      counterState = newValue.counterState
    }
  }
}

I use _screen1State and _screen2State as private storage, but only expose screen1State and screen2State, updating them on the fly.

I'm using private(set) instead of private because automatic Hashable fails with private values, at least with latest versions of Swift.

You can also check for equality before assigning in the setters to avoid useless copies.

Again, I don't know if it's the best way to achieve this kind of setup. It can be optimized for specific cases like this one, but this approach seems to work in any configuration.

Based on the responses in this post I've implemented shared state like this:

struct AppState: Equatable {
    var value: Value
    var homeState = HomeState()

    var homeValueState: SharedValueState<HomeState> {
        get {
            SharedValueState(value: value, state: homeState)
        }
        set {
            value = newValue.value
            homeState = newValue.state
        }
    }
}

struct HomeState: Equatable {
    var error: Error?
}

@dynamicMemberLookup
struct SharedValueState<State: Equatable>: Equatable {
    var value: Value
    var state: State

    subscript<LocalState>(dynamicMember keyPath: WritableKeyPath<State, LocalState>) -> LocalState {
        get { self.state[keyPath: keyPath] }
        set { self.state[keyPath: keyPath] = newValue }
    }
}

The Home reducer is of type Reducer<SharedGoalState<HomeState>, HomeAction, HomeEnvironment> and can operate on state.goal since the state is @dynamicMemberLookup.
Then the store in my view is var store: Store<SharedValueState<HomeState>, HomeAction>

With this, the source of truth for the Value instance is always the value member on AppState.

Terms of Service

Privacy Policy

Cookie Policy