You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
my question is more a architectural question than a specific Akita question. Akita is used for state management, but we do not use effects.
Scenario: We often face the issue where we have a Component that uses and displays data from multiple entity stores.
Example: Order -> OrderLine -> Product
The component has multiple ways of manipulating the data. Sometimes on all levels of the entity dependency structure. In my exmple I can manipulate the Order as well as OrderLine and Product.
So, sometime we just want to reload OrderLine and dependant entities (here: Product), sometimes we want to reload the whole Order and the dependant entities as well.
So, I came up with two possible variants how to to do this and I am not sure, what is considered "better" practice (if not both of them are "bad" ;) ):
Variant 1:
// Variant 1: More declarative approachconstloadOrderAction=newBehaviorSubject(true);constloadOrderLinesAction=newBehaviorSubject(true);constloadProductsAction=newBehaviorSubject(true);// Simulate id from route aka orderIdconstorderId=newSubject<number>();constorderId$=orderId.asObservable();// Simulation - in reality we would load data via http.get()constloadOrder=(orderId: number)=>of(orderId).pipe(tap((v)=>console.log(`http<order-${orderId}>`)));// Simulation - in reality we would load data via http.get()constloadOrderLines=(orderId: number)=>of(orderId).pipe(tap((v)=>console.log(`http<orderlines-for-${orderId}>`)));// Simulation - in reality we would load data via http.get()constloadProducts=(productIds: number[])=>of(productIds).pipe(tap((v)=>console.log(`http<products-${productIds}>`)));// Action streamsconstorder$=combineLatest([loadOrderAction.asObservable(),orderId$]).pipe(switchMap(([_,id])=>loadOrder(id)),// tap(put result into store)shareReplay(1)// <- in case we have a fork in the dependancy graph, e.g. entity1 -> entity2// -> entity3);constorderLines$=combineLatest([loadOrderLinesAction.asObservable(),order$,]).pipe(switchMap(([_,id])=>loadOrderLines(id)),// tap(put result into store));constproducts$=combineLatest([loadProductsAction.asObservable(),orderLines$,]).pipe(switchMap(([_,id])=>loadProducts(id))// tap(put result into store));
@Component({template: '''
<ng-container*ngIf="orderQuery.selectActive() | async as order">Order: {{order.name}}</ng-container>
'''
})classMyComponentimplementsOnInit{constructor(privateroute: ActivatedRoute){}ngOnInit(){// Kick it offconstload$=products$load$.subscribe()this.route.params.pipe(map((routeParams)=>+routeParams.id),).subscribe(id=>orderId.next(id));}reloadOrderLines(){loadOrderLinesAction.next(true);}}
This is a more declarative approach. Using the action Subject we can trigger the reload and make sure, that all dependant entities are loaded without thinking about.
I do not like the need for kicking the stream off (see ngOnInit). In a dependancy graph like this:
order -> orderLines && customer
We would probably kick off the main stream with combineLatest([orderLines$, customer$]).
Variant 2:
exportinterfaceActiveEntity<E>extendsEntityState<E,number>,ActiveState<number>{}declareconstorderStore: EntityStore<ActiveEntity<any>>;declareconstorderQuery: QueryEntity<ActiveEntity<any>>;declareconstorderLineStore: EntityStore<any>;// Usually placed in a serviceconstdoLoadOrder=(id: number)=>{loadOrder(id).pipe(// <- http requesttap(order=>{orderStore.upsert(order.id,order);orderStore.setActive(order.id);}),switchMap(id=>doLoadOrderLines())// <- load dependant entity)}// Usually placed in a serviceconstdoLoadOrderLines=()=>{of(orderQuery.selectActiveId()).pipe(take(1),switchMap(id=>loadOrderLines(id)),// <- http requesttap(orderLines=>orderLineStore.upsertMany(orderLines)),switchMap(orderLineIds=>loadProducts(orderLineIds))// <- load dependant entity)}
@Component({template: '''
<ng-container*ngIf="orderQuery.selectActive() | async as order">Order: {{order.name}}</ng-container>
'''
})classMyComponentimplementsOnInit{constructor(privateroute: ActivatedRoute){}ngOnInit(){this.route.params.pipe(map((routeParams)=>+routeParams.id),switchMap(id=>doLoadOrder(id))).subscribe();}reloadOrderLines(){doLoadOrderLines().subscribe();}}
In this aproach we do not have the general stream that we need to subscribe. But we need to make sure, that we name the needed dependants.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Hi,
my question is more a architectural question than a specific Akita question. Akita is used for state management, but we do not use effects.
Scenario: We often face the issue where we have a
Component
that uses and displays data from multiple entity stores.Example:
Order -> OrderLine -> Product
The component has multiple ways of manipulating the data. Sometimes on all levels of the entity dependency structure. In my exmple I can manipulate the
Order
as well asOrderLine
andProduct
.So, sometime we just want to reload
OrderLine
and dependant entities (here:Product
), sometimes we want to reload the wholeOrder
and the dependant entities as well.So, I came up with two possible variants how to to do this and I am not sure, what is considered "better" practice (if not both of them are "bad" ;) ):
Variant 1:
This is a more declarative approach. Using the action
Subject
we can trigger the reload and make sure, that all dependant entities are loaded without thinking about.I do not like the need for kicking the stream off (see
ngOnInit
). In a dependancy graph like this:We would probably kick off the main stream with
combineLatest([orderLines$, customer$])
.Variant 2:
In this aproach we do not have the general stream that we need to subscribe. But we need to make sure, that we name the needed dependants.
Suggestions and opinions welcome!
Beta Was this translation helpful? Give feedback.
All reactions