Query - withQuery
Import:
import { query } from '@ng-query/ngrx-signals';
import { rxQuery } from '@ng-query/ngrx-signals-rxjs';
What is a Query?
A query in Signal Store is used to fetch and manage server state in your Angular application. Based on Angular Resource
, it provides a reactive and declarative way to retrieve data, track its status (idle, loading, resolved, error
), and keep your UI in sync with remote resources. Queries are the foundation for building robust, user-friendly interfaces that respond to server data changes automatically.
How to Use a Query - withQuery
To use a query, you define it in your Signal Store using the withQuery
feature. You specify the resource name, a factory function that returns a query configuration, and optionally, options for client state mapping or mutation reactions.
Example
import { signalStore, withQuery } from '@ngrx/signals';
import { query } from './query';
const Store = signalStore(
withState({ id: 5 }),
withQuery('user', (store) =>
// 👇 use query or rxQuery
query({
params: store.id, // signal source
loader: ({ params }) => fetchUser(params),
})
)
);
// Inject the store and use the query resource
const store = inject(Store);
// store.userQuery (expose the `ResourceRef API`)
const user = store.userQuery.value(); // Access the fetched user
const status = store.userQuery.status(); // 'idle', 'loading', 'resolved', 'error'
Key Benefits
- Automatic status tracking (idle, loading, resolved, error)
- Reactive updates to your UI
- Easy integration with mutations and optimistic updates
- Type-safe and autocompleted in Angular
WARNING
Both query
and rxQuery
relies on signal source, only the last value emitted in very short period of time is considered. (A possible evolution is to works internally with observable when params$
from rxQuery
is used, but it is not really useful in this case). info
query
vs rxQuery
Both query
and rxQuery
are used to fetch server state in Signal Store, but they differ in how they handle data sources and reactivity:
query: Based on
resource
is designed for promise-based or synchronous data loaders. It expose allresource
functionalities.rxQuery: Based on
rxResource
is designed for observable-based data streams (RxJS). It expose allrxResource
functionalities.
query
& rxQuery
Insertions
The query
& rxQuery
accepts up to 7 insertions. These insertions can be used to add properties to the query or handle side effects. See the Insertions section in the documentation. For example, you may want to insert a custom loading state that only appears if the request takes more than 200 ms, and remains visible for at least 500 ms to avoid flakiness.
rxQuery
options
The rxQuery
function provides flexible options for configuring how your query receives parameters and streams data:
params: A function returning the parameters for the query. This is typically a signal or a value that changes reactively.
typescriptparams: signal({ id: 5 });
params$: An Observable that emits parameters for the query. Use this if your parameters come from an RxJS stream.
typescriptparams$: of('5');
stream: A function that receives the current parameters and returns an Observable of the resource data. This is where you connect to your data source (REST, GraphQL, WebSocket, etc.).
typescriptstream: ({ params }) => api.getUser(params.is); // return an Observable<User>
Example Usage
// Using params (signal or function)
rxQuery({
params: signal(5),
stream: ({ params: id }) => of({ id, name: 'John Doe' }),
});
// Using params$ (observable)
rxQuery({
params$: of('5'),
stream: ({ params: id }) => of({ id, name: 'John Doe' }),
});
Notes
- You can use either
params
orparams$
, but not both at the same time. - The
stream
function is required and should always return an Observable. - The query will automatically update its value and status whenever the parameters or the stream emit new values.