MiddlewareProtocol
public protocol MiddlewareProtocol
MiddlewareProtocol
is a plugin, or a composition of several plugins, that are assigned to the app global StoreType
pipeline in order to
handle each action received (InputActionType
), to execute side-effects in response, and eventually dispatch more actions
(OutputActionType
) in the process. It can also access the most up-to-date StateType
while handling an incoming action.
-
The Action type that this
MiddlewareProtocol
knows how to handle, so the store will forward actions of this type to this middleware.Most of the times middlewares don’t need to handle all possible actions from the whole global action tree, so we can decide to allow it to focus only on a subset of the action.
In this case, this action type can be a subset to be lifted to a global action type in order to compose with other middlewares acting on the global action of an app. Please check doc:Lifting for more details.
Declaration
Swift
associatedtype InputActionType
-
The Action type that this
MiddlewareProtocol
will eventually trigger back to the store in response of side-effects. This can be the same asInputActionType
or different, in case you want to separate your enum in requests and responses.Most of the times middlewares don’t need to dispatch all possible actions of the whole global action tree, so we can decide to allow it to dispatch only a subset of the action, or not dispatch any action at all, so the
OutputActionType
can safely be set toNever
.In this case, this action type can be a subset to be lifted to a global action type in order to compose with other middlewares acting on the global action of an app. Please check doc:Lifting for more details.
Declaration
Swift
associatedtype OutputActionType
-
The State part that this
MiddlewareProtocol
needs to read in order to make decisions. This middleware will be able to read the most up-to-dateStateType
from the store while handling an incoming action, but it can never write or make changes to it.Most of the times middlewares don’t need reading the whole global state, so we can decide to allow it to read only a subset of the state, or maybe this middleware doesn’t need to read any state, so the
StateType
can safely be set toVoid
.In this case, this state type can be a subset to be lifted to a global state in order to compose with other middlewares acting on the global state of an app. Please check doc:Lifting for more details.
Declaration
Swift
associatedtype StateType
-
Handles the incoming actions and may or not start async tasks, check the latest state at any point or dispatch additional actions.
This is a good place for side-effects such as async tasks, timers, web, database, file access, background execution, access device sensors, perform analytics, tracking, logging and telemetry. You can schedule tasks to run after the reducer changed the global state, this will happen in the
IO
closure you must return from this function.In case no side-effect is required for certain action, returning
IO/pure()
should suffice.You can only dispatch new actions to the store from inside the
IO
closure.IMPORTANT: this will be called on the main queue, never perform expensive work on it. You should perform side-effects only in the
IO
block and care about running things in background. You don’t have to return to the main queue to dispatch actions, however, the store will take care of that.Declaration
Swift
func handle(action: InputActionType, from dispatcher: ActionSource, state: @escaping GetState<StateType>) -> IO<OutputActionType>
Parameters
action
the incoming action to be handled
dispatcher
information about the action source, representing the entity that created and dispatched the action
state
a closure that, once called, will return the most up-to-date state. In the scope of this function, the state wasn’t handled by reducers yet, but in the context of the
IO
block you should expect the state to be changed already.Return Value
an
IO
closure where you can run side-effects and dispatch new actions to the store -
receiveContext(getState:
Default implementationoutput: ) Middleware setup. This function is deprecated and should never be used.
Default Implementation
Declaration
Swift
@available(*, deprecated, message: "Instead of relying on receiveContext, please use the getState from handle(action﹚ function,\nand when returning IO from the same handle(action﹚ function use the output from the closure") func receiveContext(getState: @escaping GetState<StateType>, output: AnyActionHandler<OutputActionType>)
Parameters
getState
a closure that allows the middleware to read the current state at any point in time
output
an action handler that allows the middleware to dispatch new actions at any point in time
-
eraseToAnyMiddleware()
Extension methodUndocumented
Declaration
Swift
public func eraseToAnyMiddleware() -> AnyMiddleware<InputActionType, OutputActionType, StateType>
-
lift(inputAction:
Extension methodoutputAction: state: ) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( inputAction inputActionMap: @escaping (GlobalInputActionType) -> InputActionType?, outputAction outputActionMap: @escaping (OutputActionType) -> GlobalOutputActionType, state stateMap: @escaping (GlobalStateType) -> StateType ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self>
Parameters
inputActionMap
a function that will be executed every time a global action arrives at the global store. Then you can optionally return an action of type Middleware’s local input action type so the middleware will handle this action, or you can return nil in case you want this middleware to ignore this global action. This is useful because not all middlewares will care about all global actions. Usually this is a KeyPath in an enum, such as
\GlobalAction.someSubAction?.middlewareLocalAction
when you use code generators to create enum properties.outputActionMap
a function that will translate the local actions dispatched by this middleware into a global action type for your store. Usually this is wrapping the enum in a global action tree, such as
{ GlobalAction.someSubAction(.middlewareLocalAction($0)) }
.stateMap
a function that will translate the global state of your store into the local state of this middleware. Usually this is a KeyPath in the global state struct, such as
\GlobalState.subState.middlewareLocalState
.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware. -
lift(outputAction:
Extension methodstate: ) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( outputAction outputActionMap: @escaping (OutputActionType) -> GlobalOutputActionType, state stateMap: @escaping (GlobalStateType) -> StateType ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self> where GlobalInputActionType == InputActionType
Parameters
outputActionMap
a function that will translate the local actions dispatched by this middleware into a global action type for your store. Usually this is wrapping the enum in a global action tree, such as
{ GlobalAction.someSubAction(.middlewareLocalAction($0)) }
.stateMap
a function that will translate the global state of your store into the local state of this middleware. Usually this is a KeyPath in the global state struct, such as
\GlobalState.subState.middlewareLocalState
.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware. -
lift(inputAction:
Extension methodstate: ) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( inputAction inputActionMap: @escaping (GlobalInputActionType) -> InputActionType?, state stateMap: @escaping (GlobalStateType) -> StateType ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self> where OutputActionType == GlobalOutputActionType
Parameters
inputActionMap
a function that will be executed every time a global action arrives at the global store. Then you can optionally return an action of type Middleware’s local input action type so the middleware will handle this action, or you can return nil in case you want this middleware to ignore this global action. This is useful because not all middlewares will care about all global actions. Usually this is a KeyPath in an enum, such as
\GlobalAction.someSubAction?.middlewareLocalAction
when you use code generators to create enum properties.stateMap
a function that will translate the global state of your store into the local state of this middleware. Usually this is a KeyPath in the global state struct, such as
\GlobalState.subState.middlewareLocalState
.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware. -
lift(inputAction:
Extension methodoutputAction: ) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( inputAction inputActionMap: @escaping (GlobalInputActionType) -> InputActionType?, outputAction outputActionMap: @escaping (OutputActionType) -> GlobalOutputActionType ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self> where GlobalStateType == StateType
Parameters
inputActionMap
a function that will be executed every time a global action arrives at the global store. Then you can optionally return an action of type Middleware’s local input action type so the middleware will handle this action, or you can return nil in case you want this middleware to ignore this global action. This is useful because not all middlewares will care about all global actions. Usually this is a KeyPath in an enum, such as
\GlobalAction.someSubAction?.middlewareLocalAction
when you use code generators to create enum properties.outputActionMap
a function that will translate the local actions dispatched by this middleware into a global action type for your store. Usually this is wrapping the enum in a global action tree, such as
{ GlobalAction.someSubAction(.middlewareLocalAction($0)) }
.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware. -
lift(inputAction:
Extension method) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( inputAction inputActionMap: @escaping (GlobalInputActionType) -> InputActionType? ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self> where OutputActionType == GlobalOutputActionType, GlobalStateType == StateType
Parameters
inputActionMap
a function that will be executed every time a global action arrives at the global store. Then you can optionally return an action of type Middleware’s local input action type so the middleware will handle this action, or you can return nil in case you want this middleware to ignore this global action. This is useful because not all middlewares will care about all global actions. Usually this is a KeyPath in an enum, such as
\GlobalAction.someSubAction?.middlewareLocalAction
when you use code generators to create enum properties.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware. -
lift(outputAction:
Extension method) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( outputAction outputActionMap: @escaping (OutputActionType) -> GlobalOutputActionType ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self> where GlobalInputActionType == InputActionType, GlobalStateType == StateType
Parameters
outputActionMap
a function that will translate the local actions dispatched by this middleware into a global action type for your store. Usually this is wrapping the enum in a global action tree, such as
{ GlobalAction.someSubAction(.middlewareLocalAction($0)) }
.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware. -
lift(state:
Extension method) A method used to transform a middleware focused in a specific substate into a middleware that can be plugged in a global scope and composed with other middlewares that work on different generic parameters. The global state of your app is Whole, and the
Middleware
handles Part, that is a sub-state. So for example you may want to have aGPSMiddleware
that knows about the followingstruct
:struct Location { let latitude: Double let longitude: Double }
Let’s call it
Part
. Both, this state and its middleware will be part of an external framework, used by dozens of apps. Internally probably theMiddleware
will useCoreLocation
to fetch the GPS changes, and triggers some actions. On the main app we have a global state, that we now callWhole
.struct MyGlobalState { let title: String? let listOfItems: [Item] let currentLocation: Location }
As expected,
Part
is a property ofWhole
, maybe not directly, it could be several nodes deep in the tree.Because our
Store
understandsWhole
and ourGPSMiddleware
understandsPart
, we mustlift(_:)
the middleware to theWhole
level, by using:let globalStateMiddleware = gpsMiddleware.lift(state: \MyGlobalState.currentLocation)
Now this middleware can be used within our
Store
or even composed with others. It also can be used in other apps as long as we have a way to lift it to the world ofWhole
.Declaration
Swift
public func lift<GlobalInputActionType, GlobalOutputActionType, GlobalStateType>( state stateMap: @escaping (GlobalStateType) -> StateType ) -> LiftMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, Self> where GlobalInputActionType == InputActionType, OutputActionType == GlobalOutputActionType
Parameters
stateMap
a function that will translate the global state of your store into the local state of this middleware. Usually this is a KeyPath in the global state struct, such as
\GlobalState.subState.middlewareLocalState
.Return Value
a
LiftMiddleware
that knows how to translateWhole
toPart
and vice-versa. To the external world this resulting middleware will “speak” global types to be plugged into the main Store. Internally it will “speak” the types of the wrapped middleware.
-
liftToCollection(inputAction:
Extension methodoutputAction: state: ) Undocumented
Declaration
Swift
public func liftToCollection<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, CollectionState: MutableCollection>( inputAction inputActionMap: @escaping (GlobalInputActionType) -> ElementIDAction<StateType.ID, InputActionType>?, outputAction outputActionMap: @escaping (ElementIDAction<StateType.ID, OutputActionType>) -> GlobalOutputActionType, state stateMap: @escaping (GlobalStateType) -> CollectionState ) -> LiftToCollectionMiddleware<GlobalInputActionType, GlobalOutputActionType, GlobalStateType, CollectionState, Self>
-
liftToCollection(action:
Extension methodstateCollection: ) Undocumented
Declaration
Swift
public func liftToCollection<GlobalActionType, GlobalStateType, CollectionState: MutableCollection>( action actionMap: WritableKeyPath<GlobalActionType, ElementIDAction<StateType.ID, InputActionType>?>, stateCollection: KeyPath<GlobalStateType, CollectionState> ) -> LiftToCollectionMiddleware<GlobalActionType, GlobalActionType, GlobalStateType, CollectionState, Self>