Skip to content

Reducer

tgrapperon edited this page Jun 3, 2022 · 3 revisions

Extensions on Reducer

Methods

namespace(_:)

Define an EffectID namespace for this reducer and all its descendents.

public func namespace<Namespace: Hashable>(_ namespace: Namespace) -> Self 

Namespaces allow to discern effects emanating from different instances of the same Store type running at the same time in the same process. This can happen with document-based apps where each document is supported by distinct instances of Store, each one without knowledge of the other ones. Without namespacing, the Store for the document "A" may cancel some ongoing Effects from the document "B" Store.

You ideally define a namespace for the Reducer of the root store, using some Hashable value that is unique to the Store instance, like a document identifier.

Parameters

  • namespace: some Hashable value that is unique to the store using this reducer.

Returns

A reducer that defines a namespace for identifiers defined with the @EffectID property wrapper.

namespace(_:)

Define an EffectID namespace for this reducer and all its descendents using a constant identifier extracted from State.

public func namespace<ID: Hashable>(_ id: @escaping (State) -> ID) -> Self 

Namespaces allow to discern effects emanating from different instances of the same Store type running at the same time in the same process. This can happen with document-based apps where each document is supported by distinct instances of Store, each one without knowledge of the other ones. Without namespacing, the Store for the document "A" may cancel some ongoing Effects from the document "B" Store.

You ideally define a namespace for the Reducer of the root store, using some Hashable value that is unique to the Store instance, like a document identifier.

Parameters

  • id: some Hashable value derived from State that is constant and unique to the store using this reducer. You can use any function, or a KeyPath<State, ID>.

Returns

A reducer that defines a namespace for identifiers defined with the @EffectID property wrapper.

namespace(_:)

Define an EffectID namespace for this reducer and all its descendents using a constant identifier extracted from the Environment.

public func namespace<ID: Hashable>(_ id: @escaping (Environment) -> ID) -> Self 

Namespaces allow to discern effects emanating from different instances of the same Store type running at the same time in the same process. This can happen with document-based apps where each document is supported by distinct instances of Store, each one without knowledge of the other ones. Without namespacing, the Store for the document "A" may cancel some ongoing Effects from the document "B" Store.

You ideally define a namespace for the Reducer of the root store, using some Hashable value that is unique to the Store instance, like a document identifier.

Parameters

  • id: some Hashable value derived from Environment that is constant and unique to the store using this reducer. You can use any function, or a KeyPath<Environment, ID>.

Returns

A reducer that defines a namespace for identifiers defined with the @EffectID property wrapper.

forEachNamespaced(state:action:environment:file:line:)

A version of pullback(state:​action:​environment:​) that transforms a reducer that works on an element into one that works on an identified array of elements.

public func forEachNamespaced<GlobalState, GlobalAction, GlobalEnvironment, ID>(
    state toLocalState: WritableKeyPath<GlobalState, IdentifiedArray<ID, State>>,
    action toLocalAction: CasePath<GlobalAction, (ID, Action)>,
    environment toLocalEnvironment: @escaping (GlobalEnvironment) -> Environment,
    file: StaticString = #fileID,
    line: UInt = #line
  ) -> Reducer<GlobalState, GlobalAction, GlobalEnvironment> 
// Global domain that holds a collection of local domains:
struct AppState { var todos: IdentifiedArrayOf<Todo> }
enum AppAction { case todo(id: Todo.ID, action: TodoAction) }
struct AppEnvironment { var mainQueue: AnySchedulerOf<DispatchQueue> }

// A reducer that works on a local domain:
let todoReducer = Reducer<Todo, TodoAction, TodoEnvironment> { ... }

// Pullback the local todo reducer so that it works on all of the app domain:
let appReducer = Reducer<AppState, AppAction, AppEnvironment>.combine(
  todoReducer.forEach(
    state: \.todos,
    action: /AppAction.todo(id:action:),
    environment: { _ in TodoEnvironment() }
  ),
  Reducer { state, action, environment in
    ...
  }
)

Take care when combining forEach(state:action:environment:file:line:)-gvte reducers into parent domains, as order matters. Always combine forEach(state:action:environment:file:line:)-gvte reducers before parent reducers that can modify the collection.

Parameters

  • toLocalState: A key path that can get/set a collection of State elements inside GlobalState.
  • toLocalAction: A case path that can extract/embed (Collection.Index, Action) from GlobalAction.
  • toLocalEnvironment: A function that transforms GlobalEnvironment into Environment.

Returns

A reducer that works on GlobalState, GlobalAction, GlobalEnvironment.

forEachNamespaced(state:action:environment:file:line:)

A version of pullback(state:​action:​environment:​) that transforms a reducer that works on an element into one namespaced reducer that works on a dictionary of element values.

public func forEachNamespaced<GlobalState, GlobalAction, GlobalEnvironment, Key>(
    state toLocalState: WritableKeyPath<GlobalState, [Key: State]>,
    action toLocalAction: CasePath<GlobalAction, (Key, Action)>,
    environment toLocalEnvironment: @escaping (GlobalEnvironment) -> Environment,
    file: StaticString = #fileID,
    line: UInt = #line
  ) -> Reducer<GlobalState, GlobalAction, GlobalEnvironment> 

The dictionary's key is used to namespace the element's reducer.

Take care when combining forEachNamespaced(state:action:environment:file:line:) reducers into parent domains, as order matters. Always combine forEachNamespaced(state:action:environment:file:line:) reducers before parent reducers that can modify the dictionary.

Parameters

  • toLocalState: A key path that can get/set a dictionary of State values inside GlobalState.
  • toLocalAction: A case path that can extract/embed (Key, Action) from GlobalAction.
  • toLocalEnvironment: A function that transforms GlobalEnvironment into Environment.

Returns

A reducer that works on GlobalState, GlobalAction, GlobalEnvironment.

forEachNamespaced(state:action:environment:file:line:)

A version of pullback(state:​action:​environment:​) that transforms a reducer that works on an element into one namespaced reducer that works on an identified array of elements wrapped in Identifieds.

public func forEachNamespaced<GlobalState, GlobalAction, GlobalEnvironment, ID>(
    state toLocalState: WritableKeyPath<
      GlobalState, IdentifiedArrayOf<Identified<ID, State>>
    >,
    action toLocalAction: CasePath<GlobalAction, (ID, Action)>,
    environment toLocalEnvironment: @escaping (GlobalEnvironment) -> Environment,
    file: StaticString = #fileID,
    line: UInt = #line
  ) -> Reducer<GlobalState, GlobalAction, GlobalEnvironment> 

The wrapper's Identified/id is used to namespace the element's reducer.

// Global domain that holds a collection of local domains:
struct AppState { var todos: IdentifiedArrayOf<Todo> }
enum AppAction { case todo(id: Todo.ID, action: TodoAction) }
struct AppEnvironment { var mainQueue: AnySchedulerOf<DispatchQueue> }

// A reducer that works on a local domain:
let todoReducer = Reducer<Todo, TodoAction, TodoEnvironment> { ... }

// Pullback the local todo reducer so that it works on all of the app domain:
let appReducer = Reducer<AppState, AppAction, AppEnvironment>.combine(
  todoReducer.forEach(
    state: \.todos,
    action: /AppAction.todo(id:action:),
    environment: { _ in TodoEnvironment() }
  ),
  Reducer { state, action, environment in
    ...
  }
)

Take care when combining forEach(state:action:environment:file:line:)-gvte reducers into parent domains, as order matters. Always combine forEach(state:action:environment:file:line:)-gvte reducers before parent reducers that can modify the collection.

Parameters

  • toLocalState: A key path that can get/set a collection of State elements inside GlobalState.
  • toLocalAction: A case path that can extract/embed (Collection.Index, Action) from GlobalAction.
  • toLocalEnvironment: A function that transforms GlobalEnvironment into Environment.

Returns

A reducer that works on GlobalState, GlobalAction, GlobalEnvironment.