Best Practices
The Query
Avoid creating selectors in your components:
@Component({})
class NavComponent {
isLoggedIn$ = this.authQuery.select(state => !!state.token);
constructor(private authQuery: AuthQuery) {
}
}
Instead, create them in the query:
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:
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:
- Working with Normalized Data in Akita and Angular
- Introducing One To Many Relationship in Angular & Akita
Subscription Management
A question that often comes up is whether to subscribe at the component or the service. Let's examine the two options:
class TodoService {
get() {
return this.http.get<Todo[]>('/api/todos').pipe(
tap(entities => {
this.todoStore.set(entities);
})
);
}
}
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:
class TodosComponent {
ngOnInit() {
this.todoService.get().subscribe({
next: () => {
this.success = true;
}
error: (err) => {
this.error = err;
}
});
}
}
Otherwise, you can subscribe at the service:
class TodoService {
get() {
return this.http.get<Todo[]>('/api/todos').subscribe(entities => {
this.todoStore.set(entities);
});
}
}
class TodosComponent {
ngOnInit() {
this.todoService.get();
}
}