-
Hey, Netanel! Thanks for everything you're doing for the community. I'm wondering, when I suppose to use query in my project and when Elf? I understand, that query is mainly for storing server data and Elf for everything (like NgRX). Maybe you could provide some examples when to use them and maybe compose them together) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Hey Londeren, In my opinion you can omit the entity state management on the client-side, for me it wouldn't make much sense to store them both on // client.service.ts
@Injectable({providedIn: 'root'})
export class ClientService {
public queryClientById(Id: ClientModel['Id']) {
const queryKey = ['clients', 'client', {Id}];
return this._useQuery({
queryKey,
queryFn: () => this._httpClient
.get<ClientEntity>(`redacted`)
.pipe(
catchError((error: Error) => {
this._logger.error(error);
return throwError(() => error);
}),
map(this._clientMapper.deserialize)
),
onSuccess: this._clientRepository.upsertEntities.bind(this._clientRepository), // <-- this upserts the entites returned that is passed into onSuccess
});
}
public updateClient(client: ClientModel): Observable<ClientModel> {
const serializedClient: ClientEntity = this._clientMapper.serialize(client);
return this._httpClient
.put<ClientEntity>(`redacted`, serializedClient)
.pipe(
catchError((error: Error) => {
this._logger.error(error);
return throwError(() => error);
}),
map(this._clientMapper.deserialize),
tap((updatedClient: ClientModel) => {
this._queryClient.setQueryData<ClientModel[]>(
['clients'],
(oldState = [] as ClientModel[]) => oldState
.map(entity => entity.Id === updatedClient.Id ? updatedClient : entity));
this._queryClient.setQueryData<ClientModel[]>(
['clients', 'top'],
(oldState = [] as ClientModel[]) => oldState
.map(entity => entity.Id === updatedClient.Id ? updatedClient : entity));
this._queryClient.setQueryData(['client', {Id: client.Id}], client);
this._clientRepository.updateEntity(client.Id, client);
}),
);
}
}
... Or the use with an resolver @Injectable({providedIn: 'root'})
export class ClientResolver implements Resolve<IEntityResolved<ClientModel>> {
...
public resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<IEntityResolved<ClientModel>> | Promise<IEntityResolved<ClientModel>> | IEntityResolved<ClientModel> {
const id: string | null = route.paramMap.get('id');
this._logger.debug(`Resolving client (${id})`)
if (id) {
return this._clientService.queryClientById(id).result$
.pipe(
skipWhile((result) => !result.isSuccess), // <-- this is important, because the first result returned from query is a loading result
selectResult((result): IEntityResolved<ClientModel> => {
const client = result.data as ClientModel;
this._clientRepository.setActiveEntityId(client.Id);
return ({error: null, entities: result.data as ClientModel});
})
);
}
return of({
entities: null,
error: new ValidationError($localize`Id is either null, undefined or not specified.`)
});
}
} Both of them would use Still what i suggest is that you omit the entity stores and just use |
Beta Was this translation helpful? Give feedback.
Hey Londeren,
im also using both
elf
andquery
and i undestand your dilemma.First of all tanstack did wrote about this in their documentation: https://tanstack.com/query/v4/docs/guides/does-this-replace-client-state
In my opinion you can omit the entity state management on the client-side, for me it wouldn't make much sense to store them both on
query
andelf-entities
because they could get out of sync when forgetting to update the respective entity store.But if you want to use them you could do something like this: