11# GatedMiddleware
22Turn SwiftRex middlewares on or off dynamically
33
4- Gated middleware is a middleware that holds an inner middleware that could be either active or not. The gated middleware has an internal state,
5- called ` gate state ` , that determines whether or not the inner middleware should be in ` active ` or ` bypass ` mode. This can be changed dynamically.
64
7- Every gated middleware starts with an initial gate state, called "default gate state". From that point, it will evaluate all incoming actions to
8- detect a "control action", which is an action for switching on or off the gate state. This control action is detected thanks to a control action
9- map closure or a control action map KeyPath configured in the GatedMiddleware's init, which from a given input action allows the user to inform
10- or not either this is a control action returning an Optional instance of that ControlAction (or nil in case it's a regular action).
5+ Gated middleware is a middleware that holds an inner middleware that could be either active or not.
6+
7+ There are two gate variations that can be used: by action or by state.
8+
9+ ## GatedMiddleware by action:
10+
11+ It holds an internal state, called ` gate state ` , that determines whether or not the inner middleware should be in ` active ` or ` bypass ` mode.
12+ This can be changed dynamically.
13+
14+ It starts with an initial gate state, called "default gate state". From that point on, it will evaluate all incoming actions to detect a "control
15+ action", which is an action for switching on or off the gate state. This control action is detected thanks to a control action map closure or a
16+ control action map KeyPath configured in the GatedMiddleware's init, which from a given input action allows the user to inform either or not this
17+ is a control action, by returning an Optional instance of that ControlAction (or nil in case it's a regular action).
1118
1219The init also requires some comparison values, for turnOn or turnOff the gate. If it's a control action, and it's equals to turn on, it will set
1320the inner middleware to active. If it's a control action, and it's equals to turn off, it will set the inner middleware to bypass. If it's not a
1421control action, or it's not equals to any of the comparison values, the gate will remain untouched.
1522
16- There one last important topic. The gated middleware will ALWAYS forward control actions to inner middlewares, regardless of their gate state
17- (active or bypass) and regardless of the turn on/turn off comparison result. This will allow important actions like disabling or enabling the
18- inner middleware for control actions, so for example, even for when we close the gate we still want to tell the inner middleware that it's gonna
19- be bypassed and it should kill all of its timers or async side-effects.
23+ The gated middleware by action will ALWAYS forward control actions to inner middlewares, regardless of their gate state (active or bypass) and
24+ regardless of the turn on/turn off comparison result. This will allow important actions like disabling or enabling the inner middleware for
25+ control actions, so for example, even for when we close the gate we still want to tell the inner middleware that it's gonna be bypassed and it
26+ should kill all of its timers or async side-effects.
27+
28+ ## GatedMiddleware by state:
29+
30+ It won't hold any internal state, instead, it will use some state from your App Global State. You're responsible for mutating this state from your
31+ own reducers. At any point that the state tells that this middleware is ` active ` , it's gonna handle actions and be able to dispatch new actions.
32+ However, whenever the state is set to ` bypass ` , this middleware will ignore incoming actions and won't be able to dispatch any new action.
2033
21- Example:
34+ When handling actions, the state is evaluated before reducers, so whatever state is set BEFORE reducer, will define if the inner middleware will
35+ be called before and after the reducer, even if the reducer changes that value. An action that changes the state from ` active ` to ` bypass ` , will
36+ trigger inner middleware before and after the reducer, and after the reducer that value will be already set to ` bypass ` , so you can stop timers
37+ and async tasks. An action that changes the state from ` bypass ` to ` active ` , will not trigger the inner middleware before the reducer nor after
38+ it, so you may want to send a second action to start the middleware timers again, because the gated middleware can't do that for you.
2239
40+
41+ ## Examples:
42+
43+ 1 . Gated by action, simple example
2344```
2445// sourcery: Prism
2546enum AppAction {
@@ -42,8 +63,7 @@ let gatedCrashReportsMiddleware =
4263 )
4364```
4465
45- With custom comparison:
46-
66+ 2 . Gated by action, with custom comparison:
4767```
4868// sourcery: Prism
4969enum AppAction {
@@ -57,6 +77,7 @@ enum DynamicMiddlewareAction: Equatable {
5777 case controlCrashReportsMiddleware(controlAction: MiddlewareControlAction)
5878}
5979
80+ // sourcery: Prism
6081enum MiddlewareControlAction: Equatable {
6182 case activate
6283 case bypass
@@ -78,6 +99,22 @@ let gatedCrashReportsMiddleware =
7899 // crash reports middleware regardless of its current state.
79100```
80101
102+ 3 . Gated by state, simple example
103+ ```
104+ struct AppState {
105+ var isCrashReportEnabled: Bool
106+ }
107+
108+ let gatedCrashReportsMiddleware =
109+ CrashReportsMiddleware
110+ .init()
111+ .gated(
112+ state: \AppState.isCrashReportEnabled
113+ )
114+ ```
115+
116+ ## Lift, Composed and other higher-order middlewares
117+
81118You can also lift the inner middleware before gating it, in case the AppActions or AppStates don't match. Evidently lift can also be done
82119after the gated middleware if this is what you need.
83120
@@ -88,5 +125,7 @@ the gated collection you compose them.
88125This has no interference on Reducers and this doesn't change the AppState in any way. GatedMiddleware only matches AppState with its inner
89126middleware to allow proxying the ` getState ` context.
90127
128+ ## About the examples and code generation
129+
91130All examples above use Sourcery Prism templates to simplify traversing action trees, but the ` GatedMiddleware ` offers closures in case you
92131prefer switch/case approach or other custom functions.
0 commit comments