Skip to main content
A store represents the runtime that powers the application. It is the object that you will pass around to views that need to interact with the application.

Class Definition

@MainActor
public final class Store<State, Action>

Initialization

init(initialState:reducer:withDependencies:)
initializer
Initializes a store from an initial state and a reducer.Parameters:
  • initialState: The state to start the application in
  • reducer: The reducer that powers the business logic of the application
  • prepareDependencies: A closure that can be used to override dependencies that will be accessed by the reducer
public convenience init<R: Reducer<State, Action>>(
  initialState: @autoclosure () -> R.State,
  @ReducerBuilder<State, Action> reducer: () -> R,
  withDependencies prepareDependencies: ((inout DependencyValues) -> Void)? = nil
)

Usage Example

You will typically construct a single store at the root of your application:
@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      RootView(
        store: Store(initialState: AppFeature.State()) {
          AppFeature()
        }
      )
    }
  }
}

Methods

Sending Actions

send(_:)
(Action) -> StoreTask
Sends an action to the store.This method returns a StoreTask, which represents the lifecycle of the effect started from sending an action. You can use this value to tie the effect’s lifecycle and cancellation to an asynchronous context, such as SwiftUI’s task view modifier:
.task { await store.send(.task).finish() }
Returns: A StoreTask that represents the lifecycle of the effect executed when sending the action.
send(_:animation:)
(Action, Animation?) -> StoreTask
Sends an action to the store with a given animation.Parameters:
  • action: An action
  • animation: An animation
send(_:transaction:)
(Action, Transaction) -> StoreTask
Sends an action to the store with a given transaction.Parameters:
  • action: An action
  • transaction: A transaction

Scoping

scope(state:action:)
<ChildState, ChildAction>(KeyPath<State, ChildState>, CaseKeyPath<Action, ChildAction>) -> Store<ChildState, ChildAction>
Scopes the store to one that exposes child state and actions.This can be useful for deriving new stores to hand to child views in an application:
@Reducer
struct AppFeature {
  @ObservableState
  struct State {
    var login: Login.State
    // ...
  }
  enum Action {
    case login(Login.Action)
    // ...
  }
  // ...
}

// A store that runs the entire application
let store = Store(initialState: AppFeature.State()) {
  AppFeature()
}

// Construct a login view by scoping the store
// to one that works with only login domain
LoginView(
  store: store.scope(state: \.login, action: \.login)
)
Scoping in this fashion allows you to better modularize your application.Parameters:
  • state: A key path from State to ChildState
  • action: A case key path from Action to ChildAction
Returns: A new store with its domain (state and action) transformed.

State Access

withState(_:)
<R>((_ state: State) -> R) -> R
Calls the given closure with a snapshot of the current state of the store.A lightweight way of accessing store state when state is not observable and state property is unavailable.Parameters:
  • body: A closure that takes the current state of the store as its sole argument. If the closure has a return value, that value is also used as the return value of the withState method.
Returns: The return value, if any, of the body closure.

Properties

publisher
StorePublisher<State>
A publisher that emits when state changes.This publisher supports dynamic member lookup so that you can pluck out a specific field in the state:
store.publisher.alert
  .sink { ... }

Scoping Example

For a tab view application with multiple tabs:
@Reducer
struct AppFeature {
  struct State {
    var activity: Activity.State
    var profile: Profile.State
    var search: Search.State
  }
  
  enum Action {
    case activity(Activity.Action)
    case profile(Profile.Action)
    case search(Search.Action)
  }
  // ...
}

struct AppView: View {
  let store: StoreOf<AppFeature>
  
  var body: some View {
    TabView {
      ActivityView(
        store: store.scope(state: \.activity, action: \.activity)
      )
      .tabItem { Text("Activity") }
      
      SearchView(
        store: store.scope(state: \.search, action: \.search)
      )
      .tabItem { Text("Search") }
      
      ProfileView(
        store: store.scope(state: \.profile, action: \.profile)
      )
      .tabItem { Text("Profile") }
    }
  }
}

Type Aliases

StoreOf
typealias
A convenience type alias for referring to a store of a given reducer’s domain.
public typealias StoreOf<R: Reducer> = Store<R.State, R.Action>
Instead of specifying two generics:
let store: Store<Feature.State, Feature.Action>
You can specify a single generic:
let store: StoreOf<Feature>

Supporting Types

StoreTask

public struct StoreTask: Hashable, Sendable
The type returned from Store.send(_:) that represents the lifecycle of the effect started from sending an action. Methods:
  • cancel(): Cancels the underlying task
  • finish(): Waits for the task to finish
  • isCancelled: A Boolean value that indicates whether the task should stop executing
Example:
.task { await store.send(.task).finish() }

StorePublisher

public struct StorePublisher<State>: Publisher
A publisher of store state that supports dynamic member lookup for plucking specific fields.

ObservableObject Conformance

The store conforms to ObservableObject but is not observable via the @ObservedObject property wrapper. This conformance is completely inert and its sole purpose is to allow stores to be held in SwiftUI’s @StateObject property wrapper. Instead, stores should be observed through Swift’s Observation framework (or the Perception package when targeting iOS <17) by applying the @ObservableState() macro to your feature’s state.

Build docs developers (and LLMs) love