Introduction

Akita is a simple and effective state management pattern, built on top of RxJS. Akita encourages simplicity. It saves you the hassle of creating boilerplate code and offers powerful tools with a moderate learning curve, suitable for both experienced and inexperienced developers alike.

In this article, I will share with you the result of writing the popular official ngrx-demo application with Akita. The only parts that I needed to change were the state management and the smart components interaction with the store.

This article assumes that you have at least a basic knowledge of Akita, but even if you don’t, I’m sure you’ll be able to easily go over the code.

Let the fun begin.

Building the Auth State

The Store

Akita provides two types of stores, a basic store which can hold any shape of data and an entity store which represents a flat collection of entities.

In this case, we need to use the basic store that will hold the auth state.

We created an AuthStore , provided it with the initial state and the two methods, login() and logout() responsible for updating the state.

The Query

The query is a class responsible for querying the store. In our case, we work with a basic store so we need to extend the basic Query .

The built-in select() method returns the requested slice from the state. The isLoggedIn$ property is an observable that notifies whether the current user is logged in.

The Service

Akita maintains the natural work process using Angular services, which encapsulates and manages asynchronous logic and store update calls.

Let’s see how we can use the service to update the store.

We have a login() method that updates the store and navigates the user to the root page on success, and a logout() method that clears the store.

The LoginPageComponent

Now, we can use the login() method in the login container component.

The Auth Guard

The guard checks if the user is logged in based on the value returned from the query. If they are, it will render the component, otherwise it will send them to the login page.

Building the Layout State

The ngrx demo maintains whether the side-nav is open in a layout store. Don’t ask me why, but let’s go with it and see how we do it with Akita.

As with the Auth state, we need a basic store.

The Store

We create a store that holds one key — sideNavOpen indicating the status of the side-nav. We also create the updateSideNavState() which is responsible for updating the store.

The Query

The query has one selector, sideNavOpen$ that emits whether the side nav is open.

The Service

The service setSideNavState() takes a new status and updates the store.

The App Component

Now, we can use the layout in our app component.

Building the Books State

The Store

We need to maintain a collection of books, so we’ll use an EntityStore . You can think of an entity store as a table in a database, where each table represents a flat collection of entities.

Akita’s EntityStore simplifies the process, giving you everything you need to manage it.

Let’s see how we can use it to create a books table, i.e., an EntityStore managing a Book object:

We also need to save additional information in our store

searchTerm — the last search term that the user typed in the books page. resultIds — this will keep the result ids we get from the books API call. In this case, unlike the ngrx demo, I take it further and clean the store each time we get new books. collection — a list of book ids that the users save in their collection.

We also create methods that update the corresponding key in our store. The updateCollection() method uses the built-in Akita toggle() method in order to add and remove a book id from the user collection.

The Query

Let’s create some queries.

In Akita, we have the ability to query a slice of the store as a stream, i.e. observable, or to receive it as a raw value. We can see both cases in the books query.

The Service

Let’s create a service that is responsible for communicating with our API and the store.

The searchBooks() method calls the built-in store setLoading() method that updates the loading key in our store.

Next, we need to fetch the books from the API, remove them from the store books that aren’t in the user collection using the built-in remove() method, add new books with the built-in add() method, update the resultIds key and set the loading back to false.

The remaining methods are self-explanatory, so I will not go over them.

Now, let’s use all this goodness in our components.

The CollectionPageComponent

my collection

We are using the built-in selectMany() query method from Akita in order to get the user collection.

The ViewBookPageComponent

book page

We are using the built-in Akita store method setActive() in order to set the active book according to the id we receive from the router.

The SelectedBookPageComponent

We are using the built-in selectActive() query method from Akita in order to get the active book from the store.

We are using the isInCollection$ query that we created earlier to toggle the add/remove book button.

Last, we are using the booksService in order to add or remove books from the collection.

The FindBookPageComponent

We need to enter the last search term into the search component once, therefore there is no need to reactively get the value, and so we are querying the value once from the store.

We need to show a spinner while we fetch the books so we are using the built-in selectLoading() query method, which will notify us when to show the spinner.

We are listening to search term changes in our store and fetching the books accordingly. We use skip(1) to skip the first call.

The last thing we need to do is query the books and display them in the view. We are using the selectResultIds query to filter books that exist in the user collection but not in the search results.

That’s all folks. Here is the full working demo of the application:

Summary

We’ve seen here how the various core concepts of Akita work together to give us an easy way to manage a bookstore. This is only a small taste of Akita; it has many more additional features, such as powerful plugins, dev tools, cli, support for active state, transactions, web workers, etc.

I encourage you to explore the API by reading the docs and the source code of the demo application.

Use Akita, It will make your life easier

Here is more great content about Akita: