Suas is a unidirectional data flow architecture implementation for iOS/macOS/tvOS/watchOS and Android heavily inspired by Redux. It provides an easy-to-use library that helps to create applications that are consistent, deterministic, and scalable.
Suas focuses on providing good developer experience and tooling such as customizable logging and state changes monitoring.
Join our gitter chat channel for any questions. Or check Suas documentatation website.
- Suas application flow and components
- Why use Suas
- Getting Started
- Installation
- Developer experience and tooling
- Example applications built with Suas
- Where to go next
- Contributing
- Contact us
- Suas future
For more in depth documentation on how to use Suas check Suas website, Suas API Interface or go straight to a list of applications built with Suas.
Suas architecture is composed of five core elements:
- Store: main component that contains a Reducer (or set of reducers), and the main application State. Listeners subscribe to it for state changes. Actions that cause state changes are dispatched to it.
- State: defines the state of a component/screen or group of components/screens.
- Action: each action specifies a change we want to effect on the state.
- Reducer: contains the logic to alter the state based on a specific action received.
- Listener: callback that gets notified when the state changes.
The following animation describes the Suas runtime flow.
Suas helps you to build highly-dynamic, consistent mobile applications:
- Cross platform; Suas-iOS works on iOS, macOS, tvOS and watchOS. Suas-Android works on all API levels and provides a Kotlin-friendly interface.
- Focuses on developer experience with plugins/tools like LoggerMiddleware and Suas Monitor.
- Small code base with low operational footprint. Check the source code 🙂.
- Static typing and type information are conserved in the Store, Reducers, and Listeners.
- Fast out of the box, and can be customized by developers to be even faster with filtering listeners.
Suas on the iOS can be installed with Carthage or CocoaPods
Open your Cartfile
and append the following:
github "zendesk/suas-ios"
And then build it with carthage update --platform ...
Add pod 'Suas'
to your Podfile
.
use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
pod 'Suas'
Then run pod install
Let's get started by building a counter application.
When building applications in Suas, we start by defining the state for our counter. In this example, the counter state is a struct that contains the counter value.
struct Counter {
var value: Int
}
We then define the actions that affect the state. For the counter, we need increment and decrement actions.
struct IncrementAction: Action {
let incrementValue: Int
}
struct DecrementAction: Action {
let decrementValue: Int
}
Now that we have both the State
and the Actions
, we need to specify how actions are going to affect the state. This logic is implemented in the reducer. The counter state reducer looks like the following:
struct CounterReducer: Reducer {
var initialState = Counter(value: 0)
func reduce(state: CounterReducer.StateType, action: Action) -> CounterReducer.StateType? {
// Handle each action
if let action = action as? IncrementAction {
var newState = state
newState.value += action.incrementValue
return newState
}
if let action = action as? DecrementAction {
var newState = state
newState.value -= action.decrementValue
return newState
}
// Important: If action does not affec the state, return ni
return nil
}
}
The reducer defines two things:
- The initial state for the store. i.e. the initial
Counter
value. - The reduce function, which receives both the dispatched
Action
and the currentState
. This function decides whatState
to return based on theAction
. If the reducer did not change the state, it should returnnil
The Store
is the main component we interact with in the application. The store contains:
- The application's state.
- The reducer, or reducers.
- (Advanced) The middlewares
We create a store with the following snippet:
let store = Suas.createStore(reducer: counterReducer)
Now we can dispatch actions to it and add listeners to it. Let's look at our UI.
class CounterViewController: UIViewController {
@IBOutlet weak var counterValue: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Finally: Use the store
self.counterValue.text = "\(store.state.value(forKeyOfType: Counter.self)!.value)"
// Add a listener to the store
// Notice the [weak self] so we dont leak listeners
let subscription = store.addListener(forStateType: Counter.self) { [weak self] state in
self?.counterValue.text = "\(state.value)"
}
// When this object is deallocated, the listener will be removed
// Alternatively, you have to delete it by hand `subscription.removeListener()`
subscription.linkLifeCycleTo(object: self)
}
@IBAction func incrementTapped(_ sender: Any) {
// Dispatch actions to the store
store.dispatch(action: IncrementAction(incrementValue: 1))
}
@IBAction func decrementTapped(_ sender: Any) {
// Dispatch actions to the store
store.dispatch(action: DecrementAction(decrementValue: 1))
}
}
Let's break down the code above:
- We add a listener to the store by calling
store.addListener(forStateType: Counter.self)
specifying the state type. Notice that we Must use[weak self]
reference in the callback block to prevent strong memory cycles. - By calling
subscription.linkLifeCycleTo(object: self)
we link the listener lifecycle to the view controller. When the controller is deallocated the listener is removed. - Tapping on the increase or decrease button dispatches actions with
store.dispatch(action:)
that change the state.
That's it, check our documentation website for a full reference on Suas components and check the list of example built using Suas.
Suas focuses on developer experience and tooling. It provides two plugins in the form of Middlewares out of the box.
While the LoggerMiddleware
logs all the action received with the state changes.
Read more about how to use the LoggerMiddleware.
The MonitorMiddleware
helps to track state transition and action dispatch history.
When using MonitorMiddleware
the Action
dispatched and State
changes are sent to our Suas Monitor desktop application.
Read how to install and start using the MonitorMiddleware
by heading to getting started with monitor middleware article.
Under the hood Suas Monitor
uses the fantastic Redux DevTools to provide state and action information.
Check Suas website for an updated list of examples built with Suas.
To get more information about Suas:
- Head to Suas website for more in-depth knowledge about how to use Suas.
- Check the Suas API refrerence.
- Read through how to use Suas by checking some examples built with Suas.
- Join the conversation on Suas gitter channel or get in touch with the people behind Suas.
We love any sort of contribution. From changing the internals of how Suas works, changing Suas methods and public API, changing readmes and documentation topics.
Feel free to suggest changes on the GitHub repos or directly in Saus gitter channel.
For reference check our contributing guidelines.
Join our gitter channel to talk to other Suas developers.
For any question, suggestion, or just to say hi, you can find the core team on twitter:
To help craft Suas future releases, join us on gitter channel.
Copyright 2017 Zendesk, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.