I'm just starting to learn ngrx signals and one thing that struck me is that a "store" file could become quite large, quite quickly so ideally I would like to break it into separate parts.
Below is an example of how I might split out the "withMethods" factory but I cannot work out what the type of "store" should be in the bookMethodsFactory
function and how I can avoid a circular dependency?
import { inject } from '@angular/core';
import { patchState, signalStore, withMethods, withState } from '@ngrx/signals';
// book.model.ts
export interface Book {
id: number;
title: string;
}
// books.service.ts
export class BooksService {
public getBooks(): Promise<Book[]> {
return Promise.resolve([
{ id: 1, title: 'Book 1' },
{ id: 2, title: 'Book 2' },
{ id: 3, title: 'Book 3' }
]);
}
}
type BooksState = {
books: Book[];
};
// book
const initialState: BooksState = {
books: []
};
export const BooksStore = signalStore(
{ protectedState: false },
withState(initialState),
withMethods(bookMethodsFactory)
);
// book.methods.ts
export const bookMethodsFactory = ((store: ???) => {
const bookService = inject(BooksService);
return {
async loadBooks(): Promise<void> {
const books = await bookService.getBooks();
patchState(store, { books });
}
}
});
In NGRX signal store you can create an extension using signalStoreFeature. It can be used in your case if you have a long list of withMethods functions, or you can use it to share code between signals stores.
So in your case, you can create a separate file book.signalMethods.ts
import { signalStoreFeature, withMethods } from '@ngrx/signals';
export function withMySeparatedMethods() {
return signalStoreFeature(
withMethods((store, bookService = inject(BooksService)) => {
//loadBooks
// function2
// function3
return { loadBooks, function2, function3 };
})
)
}
then all what you need to do is to import it in your main signal store
export const BooksStore = signalStore(
{ protectedState: false },
withState(initialState),
withMySeparatedMethods() // HERE
);