Our use case: in a component, we compute queries for data that should be fetched based on some config. I tried creating rxResource()
within a compute to get the data - but also loading status and errors for each query individually.
private readonly dataQueries = computed<DataQuery[]>(() => {
// compute queries from component state
});
private readonly dataResources = linkedSignal<
DataQuery[],
DataResource[]
>({
source: this.dataQueries,
computation: (newQueries, previousResult) => {
// iterate over all queries and
// check if we have a resource already for a query,
// if yes, reuse the rxResource for it,
// otherwise create a new one
}
}).asReadonly();
protected readonly dataResults = computed<DataResults[]>(() =>
this.dataResources().map((r) => r.value())
);
protected readonly dataStatuses = computed<ResourceStatus[]>(() =>
this.dataResources().map((r) => r.status())
);
However, this approach has two main drawbacks:
rxResource
uses internally effect()
when constructed, and this is not allowed during computation of a signal value (and for a good reason, I agree, as in most cases this is not what you want)linkedSignal
to cache previous results in order to avoid re-creating resources for queries that existed already (ngxtensions's extendedCompute
is deprecated now and suggests to use a linkedSignal
instead)I could use a single rxResouce
that holds the combined results - but I then loose the individual status and error state information.
The classical approach would be to use Observables, I guess, and add loading state and errors to the results before assembling them into the final array. But as the resource()
is a very nice way to combine value, state, and errors, it would be nice, if I could use this for each query.
Do I miss something? Any suggestions?
You approach is fundamentally flawed as far as my understanding goes.
The resource
APIs in general are initializer APIs, which are defined on the class top level (Same level as properties) or in the constructor, the point I want to make is, Define the resource API only once and never place it inside a reactive context, because it itself is a reactive element.
The resource API is a reactive entity, that is supposed to be defined once and should react to signal changes.
It has no place inside a computed
, because it can achieve reactivity by itself without relying on computed.
Each time the signals inside the computed
change, a new instance of resource
is created (Absolutely no benefit but guaranteed memory leak).
So please initialize your resource as the top most level of reactivity.
Then we can use computed
or linkedSignal
to derive the subsequent states required by the component.
Basically you need to make a normal http call and not use the resource
API, since this does not feel like a good use case for the resource
API.