Best Practices

The Query

Avoid creating selectors in your components:

nav.component.ts
@Component({})
class NavComponent {
isLoggedIn$ = this.authQuery.select(state => !!state.token);
constructor(private authQuery: AuthQuery) {
}
}

Instead, create them in the query:

auth.query.ts
export class AuthQuery extends Query<AuthState> {
isLoggedIn$ = this.select(state => !!state.token);
constructor(protected store: AuthStore) {
super(store);
}
}

This makes your components cleaner and the selectors reusable across the application.

Data Storage Types

Store only plain objects in the store, avoid storing Map or Set. It's more efficient to perform immutable operations (which are required for updating the store) with plain objects rather than with complex ones such as Map or Set. Moreover, it's harder to serialize this types of objects.

UI State

Keep the UI data separated from the model data. Read more about this topic here.

Keep It Simple

Avoid over-engineering. Don't create a separate store for any entity you may have. For example, you might have a list of articles where each article contains a list of comments:

articles.store.ts
interface Article {
id: ID;
comments: Comment[];
title: string;
}
interface ArticlesState extends EntityState<Article> {
}
@StoreConfig({ name: 'articles' })
class ArticlesStore extends EntityStore<ArticlesState> {
constructor() {
super();
}
}

In most cases, there is no need to create a separate entity store for the comments. Instead use Akita's Array Utils. This will keep your store easier to maintain and use. If you still require a separate store, check out this article for tips on how to combine their data:

Subscription Management

A question that often comes up is whether to subscribe at the component or the service. Let's examine the two options:

todos.service.ts
class TodoService {
get() {
return this.http.get<Todo[]>('/api/todos').pipe(
tap(entities => {
this.todoStore.set(entities);
})
);
}
}
todos.components.ts
class TodosComponent {
ngOnInit() {
this.todoService.get().subscribe();
}
}

Prefer this option when you need to show the user a success or error message locally in the component:

todos.components.ts
class TodosComponent {
ngOnInit() {
this.todoService.get().subscribe({
next: () => {
this.success = true;
}
error: (err) => {
this.error = err;
}
});
}
}

Otherwise, you can subscribe at the service:

todos.service.ts
class TodoService {
get() {
return this.http.get<Todo[]>('/api/todos').subscribe(entities => {
this.todoStore.set(entities);
});
}
}
todos.components.ts
class TodosComponent {
ngOnInit() {
this.todoService.get();
}
}