Listener
The final step covers listening to state changes. We do that by adding listeners to the Store.

Adding a listener
In our todo app example, we can add a listener that gets notified whenever the todo list items change:
let subscription = store.addListener(forStateType: TodoList.self) { state in
// Use the state in a view
someView.state = state
}
val subscription = store.addListener(TodoList::class.java, { state ->
// Use the state in a view
someView.state = state;
})
Subscription subscription = store.addListener(TodoList.class, state -> {
// Use the state in a view
someView.update(state);
});
When adding the listener, we can also pass a filter block that decides whether to notify the listener or not.
For instance, we can add a listener that gets notified if the number of todo items is bigger than 2:
let subscription = store.addListener(
forStateType: TodoList.self,
if: { oldState, newState in newState.todos.count > 2 }
) { state in
print("Other listener called \(state.todos)")
}
val subscription = store.addListener(
TodoList::class.java,
{ oldState, newStat -> newStat.todos.size > 2 }
) { state ->
println("Other listener called ${state.todos}")
}
store.addListener(
TodoList.class,
(oldState, newState) -> newState.todos.size() > 2,
state -> {
System.out.println("Other listener called " + state);
});
The filter is a function that receives both the oldState
and the newState
. If you return true from the filter, the listener will be notified, otherwise, it will be skipped. We cover the filtering of listeners in greater length in filtering listeners page.
Using the Subscription
When calling addListener
we get a subscription
back. This subscription
can be used to remove the listener when we're done with it.
subscription.removeListener()
subscription.removeListener()
subscription.removeListener();
We also use the subscription
to trigger a manual notification to the listener about the currently held state
in the store
.
let subscription = store.addListener(forStateType: TodoList.self) {...}
// Later inform about the current state
subscription.informWithCurrentState()
val subscription = store.addListener(TodoList::class.java) { }
// Later inform about the current state
subscription.informWithCurrentState()
Subscription subscription = store.addListener(TodoList.class, state -> { ... });
// Later inform about the current state
subscription.informWithCurrentState();
Calling informWithCurrentState
on the subscription
invokes the listener callback block with whatever state
the store
currently have. This can be used to force trigger the listener notification block without dispatching an action
to the store
.
iOS Only: Linking the listener lifecycle to an object
Finally, the subscription
can be used to link the listener life cycle to an object. When the linked object is deallocated, so is the listener.
For example, we can create a listener that updates our TodoView
with the new state. Instead of remembering to remove the listener when the TodoView
is deallocated, we can link the listener
to the TodoView
:
// The TodoView
let todoView = ...
let subscription = store.addListener(forStateType: TodoList.self) { state in
// Setting the state in the view
todoView.state = state
}
// Connect the listener lifecycle to the todoView
subscription.linkLifeCycleTo(object: todoView)
When the TodoView
gets removed from the screen and gets deallocated, the listener
will be removed from the store.
iOS: Using Weak self in Listeners
If you are using self inside the listener notification, make sure to capture self weakly.
let subscription = store.addListener(forStateType: TodoList.self) { [weak self] state in // Setting the state in the view self?.state = state }
This is important to prevent strong memory cycles that lead to leaking.
State Converters
When adding a listener, we can customize the notification process by passing a stateConverter
. Setting the state converter is covered in Using the StateConverter page.
Action Listeners
Sometimes you might need to be informed when a particular action happens. Especially when the action is intended to alert the UI about a change that is not related to any particular State
. In these cases, you can add an ActionListener
.
let subscription = store.addActionListener { action in
// When any action occurs, this callback will invoked
if action is SomeAction {
// Do something with the action
// Notice that we only get the action here
}
}
val subscription = store.addListener<Any>("someAction") { state ->
// Do something with the action
}
Subscription subscription = store.addListener("someAction", state -> {
// Do something with the action
});
ActionListeners
you add are informed about any action dispatched to the store. The notification of the action happens before the action is sent to the middlewares or the reducer.
At a later time, as with the Listener
, we need to remove the action listener by calling:
subscription.removeListener()
subscription.removeListener()
subscription.removeListener();
In the iOS version of Suas, also as in Listener
, you can link the life cycle of the action listener with an object so that when the object is deallocated, the action listener is deallocated too. This is done by calling linkLifeCycleTo
on the subscription
.
// The TodoView
let todoView = ...
let subscription = store.addActionListener { ... }
// Connect the listener lifecycle to the todoView
subscription.linkLifeCycleTo(object: todoView)
iOS: Using Weak self in Listeners
If you are using self inside the listener notification, make sure to capture self weakly.
let subscription = store.addActionListener { [weak self] action in // use self }
This is important to prevent strong memory cycles that lead to leaking.
Note on more advanced usages
If your application contains multiple screens that are not logically or functionally tied; for example, in your todo app you might have a settings screen. In this case, you can add listeners to a specific type (or path) of the state. Head to applications with multiple states to learn more.
What's Next
This concludes our exploration of Suas core concepts. Head to filtering listeners to read about how to customize the listener notification logic.
Alternatively, read about how you can further customize the Suas store dispatching logic by using middlewares.
Finally, check the list of examples built with Suas.
Related Topics
Advanced topics
Applications with multiple states
Async Actions
Filtering Listener
Updated about 6 years ago