Storing The Last Dispatched Action In Aurelia Store

Another day, another Aurelia Store tip/hack. Recently, I encountered an interesting situation where I wanted to know when a specific action has fired, being able to check for it within my state subscriptions.

Now, it is highly likely there is a better way to do this. RxJS is quite magical and has a seemingly bottomless trove of treasures and ways to work with observables and data.

The use case is simple. Inside of my subscriptions, I want to know if a specific action has fired and in some cases, what the parameters for said action were. I decided this was the perfect use case for an Aurelia Store middleware.

function lastCalledActionMiddleware(state: State, originalState: State, settings = {}, action: CallingAction) {
    state.$action = {
        name: action.name,
        params: action.params ?? {}
    };

    return state;
}

This is the middleware function and registration. It sets a property defined in your state called $action which stores the currently fired action passing through the middleware as well as the parameters supplied. I prefix with a $ to make the chances of it being overwritten elsewhere highly unlikely.

When registering the middleware, I only want to know when it has fired. So, I choose to place it after.

this.store.registerMiddleware(lastCalledActionMiddleware, MiddlewarePlacement.After);

As you can see below in Redux Developer Tools, my property is being stored and the parameters supplied to the dispatched action.

If you know of a better way to do this, I would love to hear about it. For my use cases, this works quite well and fine. A middleware seems like the perfect use case for something like this.

Implementing A Method To Get Single Values In Aurelia Store

The Aurelia Store plugin is a great way to add powerful and easy to use state management into your Aurelia applications. For some, the paradigm shift in how you work can be confusing to work with at first. One such task you might find yourself needing to do is obtaining a singular value from the state.

As you will soon discover, state management in Aurelia Store requires you to subscribe to the entire state and react to all changes. Sometimes you just want to get a single value from the state to reference inside of your view-models.

While I cannot guarantee Vildan (Aurelia core team member and author of Aurelia Store) will approve of my solution, it works 😂

The solution I came up with which fits my needs perfectly is a method to subscribe, get one or more values from the state and then unsubscribe.

export const getStatePropertyOnce = async (...properties: string[]) => {
  return new Promise(async (resolve, reject) => {
    const subscription = store.state.pipe(pluck(...properties)).subscribe(
      (value) => { resolve(value); },
      (error) => { reject(error); }
    );
    subscription.unsubscribe();
  });
};

The beautiful thing about this method is it not only supports top-level properties, but it also works for nested properties in your state object as well. In a real use case, I have the locality value of the user’s client stored in the state.

async getAppClient() {
    this.appClient = await getStatePropertyOnce('appClient');
} 

There might be some pitfalls I have yet to encounter with the above functionality and you should also make sure your await is wrapped in a try/catch block as well to handle errors, but it works for my needs. If the thought of having to use @connectTo or manually setup a subscriber and then dispose of it within your view-models sounds like a lot of work, this helper method can be a good time saver.

async getValueFromStore() {
    // Object in state is represented as user.details.email
    this.someValue = await getStatePropertyOnce('user', 'details', 'email');
} 

In the above example, we are using the method to get a property of email which exists on an object called details which lives inside of a main user object. The method handles getting nested properties with ease.