Swift implementation of Redux
SwiftyRedux tries to stay as close to Redux.js with its ideas and API as possible. It should be easier to use this tool and understand approach within iOS platform by sharing same vocabulary and having such a great community in js world! There will be minor differences though due to the languages and platforms distinctions.
SwiftyRedux has few core components:
-
State is a single data structure. It is a source of truth of our application. Store can be a struct or enum, it may contain other structs or enums as properties. Often it is a deeply nested object that describes your whole application state. Keep in mind that state should be easily serialized and deserialized, thus not contain any behavior. State is managed by the store.
-
Store is a place that contains state. It also allows subscribing to the state changes and dispatching actions to change its state. There's only single store in the whole Redux application.
-
Action is a plain object that represents an intention to change the state. Actions should not contain any behavior. All actions should conform to the empty
Action
protocol. The only way to change state is through action that will be handled in reducers. -
Reducer is the only place that can change the state based on the current state and an acion. Reducers must be pure functions - functions that return the exact same output for given inputs, thus not performing any side effects. It makes them easy to test and reason about the logic that affects global application state. Store is responsible for delivering actions to the reducers and updating state with their results.
-
Middleware is a place where you keep async logic and side effects. It's the best way to connect IO with pure unidirectional flow application. They intercept actions after they were dispatched and before they reached reducers, but you can design your middlewares in such a way they don't slow down delivery of actions to the reducers.
Please refer to https://redux.js.org/introduction/getting-started for more info about this approach in general and Redux.js community experience.
Usually your flow will match current diagram:
- You dispatch an Action via the Store.
- Action travels to the Middleware.
- Middlewares might dispatch a new Action (which will travel all they way from the very beginning) or propagates it further.
- Reducers receive the Action and the current State.
- They might apply the Action to the State to return a New State, or ignore it if no changes required.
- After the state was changed, any Observers will receive it.
- In case of UI observers, Presenters can transform state or its parts into Props and give it to their Views to render.
- Any user action or program events can be turned into Actions and will be dispatched to the Store to start this cycle from the beginning.
You can install SwiftyRedux via CocoaPods by adding it to your Podfile:
pod 'SwiftyRedux'
And running pod install
.
TBD
.package(url: "https://github.com/a-voronov/swifty-redux.git", from: "0.4.0")
There's also an Example app, so you can play around with SwiftyRedux. In order to start using it:
- Open
Example/Example.xcworkspace
. - Run
Example
scheme. - Check
Debug Area
.
You can find sample code in the ExampleApp.swift
file.
SwiftyRedux is trying to be as minimalistic at its Core as possible, yet still open for extensions on top of it.
Here are components included in this repo:
Core is a basic component and contains minimal needed functionality to enjoy SwiftyRedux :)
Such as Action
, Reducer
, Middlerware
, Store
and Disposable
.
pod 'SwiftyRedux/Core'
Steroids is an extension that provides declarative API to transform state updates coming from the store. Its Observable
and ObservableProducer
abstractions look and behave similar to ReactiveSwift Signal
and SignalProducer
.
pod 'SwiftyRedux/Steroids'
Batched Actions provide ability to send multiple actions at once and split them into single actions either with upgraded reducer or own middleware (not both though). Inspired by redux-batched-actions.
pod 'SwiftyRedux/BatchedActions'
Side effects is a kind of middleware that is run after reducers have received and processed the action, so that, they can't "swallow" or delay it. Inspired by redux-observable.Epics but this is an "imperative" epics.
pod 'SwiftyRedux/SideEffects'
Commands are simple wrappers over functions that contain additional callee meta information for easier debugging.
pod 'SwiftyRedux/Command'
Actually epics' implementation is close to redux-observable.Epics but without fancy functionality like adding epics asynchronously/lazily yet. It is powered by ReactiveSwift to provide full reactive experience while transforming actions.
pod 'SwiftyRedux/Epics'
Bridge between ReactiveSwift and SwiftyRedux: Observable
<> Signal
, ObservableProducer
<> SignalProducer
.
This one depends on ReactiveSwift and Steroids.
pod 'SwiftyRedux/ReactiveExtensions'
All of these components already have Core as their dependecy, thus you can install any of them as shown above.
You can also mix any of them together and install many at once, i.e.:
pod 'SwiftyRedux', :subspecs => ['Core', 'Steroids', 'SideEffects', 'BatchedActions']
Note: since SPM doesn't support anything close to subspecs, there're only 3 main products available - SwiftyRedux, SwiftyReduxEpics, SwiftyReduxReactiveExtensions
.
SwiftyRedux is available under the MIT license. See the LICENSE file for more info.