Async Actions

Sometimes your action might need to perform some work in the background asynchronously. For instance, you might want to dispatch an action that calculates some value and stores it to disk asynchronously, or another action that loads a resource from the network asynchronously and displays it in a view.

For these situations, Suas provides AsyncAction and AsyncMiddleware.

To use AsyncActions you have to do the following.

  1. Pass the AsyncMiddleware when creating the store.
let store = Suas.createStore(reducer: ..., 
                          middleware: AsyncMiddleware() + LoggerMiddleware())
val store = Suas.createStore(reducers)
                .withMiddleware(AsyncMiddleware(), logger)
                .build()
Store store = Suas.createStore(reducers)
        .withMiddleware(new AsyncMiddleware(), logger)
        .build();

Notice how we passed two middlewares. The AsyncMiddleware, since it appears first, gets the action dispatched before the LoggerMiddleware.

  1. Create an action that implements the AsyncAction. The recipe for an AsyncAction looks like this
struct MyAsyncAction: AsyncAction {

  func execute(getState: @escaping GetStateFunction, dispatch: @escaping DispatchFunction) {
    // Dispatch some pre execution action
    // Example: tell the UI to display an activiy indicator
    let somePreAction = PreAction()
    dispatch(somePreAction)
    
    // Do some work on the current thread
    // Or do it on the background thread
    someBackgroundThreadOperation().onCompleted { someResult in

      // Create some new action with the result
      let action = SomeNewAction(result: someResult)
      
      // Dispatch the action to inform the listeners about the result
      dispatch(action)
    }
  }
}
class MyAsyncAction : AsyncAction {
    override fun execute(dispatcher: Dispatcher, getState: GetState) {
        // Dispatch some pre execution action
        // Example: tell the UI to display an activiy indicator
        val somePreAction = PreAction()
        dispatcher.dispatch(somePreAction)

        // Do some work on the current thread
        // Or do it on the background thread
        someBackgroundThreadOperation().onComplete(object : ResultHandler {
            override fun onComplete(result: String) {
                // Create some new action with the result
                val someNewAction = SomeNewAction(result)
                // Dispatch the action to inform the listeners about the result
                dispatcher.dispatch(someNewAction)
            }
        })
    }
}
class MyAsyncAction implements AsyncAction {

    @Override
    public void execute(Dispatcher dispatcher, GetState getState) {
        // Dispatch some pre execution action
        // Example: tell the UI to display an activiy indicator
        PreAction somePreAction = new PreAction();
        dispatcher.dispatch(somePreAction);

        // Do some work on the current thread
        // Or do it on the background thread
        someBackgroundThreadOperation().onComplete(result -> {
            // Create some new action with the result
            SomeNewAction someNewAction = new SomeNewAction(result);
            // Dispatch the action to inform the listeners about the result
            dispatcher.dispatch(someNewAction);
        });
    }
}

When an AsyncAction is dispatched to the store, the AsyncMiddleware receives it. Upon receiving the AsyncAction, the AsyncMiddleware, performs the action by calling it's execute and stop propagating it (so other middlewares and the reducer won't get the action).

In order to implement the AsyncAction protocol, a struct/class has to implement the execute function. This function gets called with two params:

  • getState: a function that when called returns the current Store state. This function is analogous to store.state`.
  • dispatch: a function that dispatches the action to the store. This function is analogous to store.dispatch(action:)`.

In the execute function we generally do the following:

  • We can use dispatch parameter passed to dispatch actions to the store. This could be an action that tells the UI that we need to display an activity indicator for example.
  • We then perform an operation asynchronously. Such as loading a network resource, or writing and reading from disk asynchronously.
  • When the operation is finished, we dispatch an action that updates the UI with some data. It can, for example, also tells the UI to remove the activity indicator we added before performing the asynchronous work.

What's Next

Check the search cities application example for a more detailed example on how to use AsyncActions and the AsyncMiddleware.

Check these three examples on how to implement AsyncAction:

Related Topics

Using middlewares
Logging in Suas
Using Suas Monitor