josh-sachs
josh-sachs

Reputation: 1819

NGRX Effects - Where/How to organize effect definitions.

I'm using @ngrx/effects in an angular2 application, and struggling with the organization of the different effect definitions.

I have to entities, Identity and Subscription, each with their own Actions services IdentityActions, SubscriptionActions, as well as their effects services IdentityEffects, SubscriptionEffects.

The following actions are defined.

IdentityActions.AuthorizeIdentity()
IdentityActions.OnIdentityAuthorized(identity)
SubscriptionActions.GetSubscriptionList(identity)
SubscriptionACtions.OnSubscriptionsListed(subscriptions)

After an identity is authorized, I immediately want to get a list of it's subscriptions. How does @ngrx/effects advocate the organization of these effects so that it is traceable/easy-to-find later (e.g. a year from now)?

In IdentityEffects:

@Effect()
this._actions.ofType(authActions.AUTHORIZE_IDENTITY))
  .switchMap(() => this.svc.AsyncAuth())
  .switchMap((identity) => authActions.OnIdentityAuthorized(identity))

@Effect()
this._actions.ofType(authActions.ON_IDENTITY_AUTHORIZED)
  .switchMap((identity) => Observable.of(action, subActions.GetSubscriptionList(identty)) 

This seems natural when writing it, because getting the subscription list is an effect of an identity getting authorized... but I'm concerned because if a developer is ever trying to track down where the subscription list is getting fetched from, it isn't intuitive to go digging around in the IdentityService.

The alternative is to register a 2nd effect in CustomerEffects that doesn't emit..

@Effect({emit: false})
this._actoions.ofType(authActions.ON_IDENTITY_AUTHORIZED)
  .switchMap((identity) => Observable.of(action, subActions.GetSubscriptionList(identity)) 

This seems like it would be easier to find in the long run... But feels less natural when writing it (I'm writing an identity side effect in the subscriptions service...)

What is the time-tested approach (if there even exists enough time)?

Upvotes: 2

Views: 670

Answers (1)

josh-sachs
josh-sachs

Reputation: 1819

Not really a ton of great feedback here but I want to follow up with the direction I went.

I decided that it makes the most sense to group effects by the entity that is effected, rather than by what causes the effect.

95% of the time, this results in an effects service definition that pertains to exactly one entity... in some instances however there may be one or two effects that reference something else.

In my example, an Identity is authenticated, and that causes subscriptions to get loaded.

IdentityEffectsService.ts

@Effect()
public AuthorizeIdentity$ = this._actions.ofType(AUTHORIZE_IDENTITY)
  .switchMap(() => this._identitySvc.Authorize())
  .map(identity => this._identityActions.OnIdentityAuthorized(identity))

@Effect()
Public OnIdentityAuthorized$ = this._actions.ofType(ON_IDENTITY_AUTHORIZED)
  .do(identity => console.log(`${identity.name}` logged in!`));

SubscriptionActionsService.ts

@Effect() ListSubscriptions$ = this._actions.ofType(LIST_SUBSCRIPTIONS)
  .map(action => <Identity>action.payload)
  .switchMap(identity=> this._subscriptionSvc.List(identity))
  .map((subs) => this._subscriptionActions.OnSubscriptionsListed(subs))

@Effect() OnSubscriptionsListed$ = this._actions.ofType(ON_SUBSCRIPTIONS_LISTED)
  .do(action => console.log(`${action.payload.length} subscriptions listed.`)

/ * This was the effect in question.
    I've grouped it with the other subscription effects because I believe it
    will be more natural for someone trying to understand how subscriptions
    get filled to find it here in the future. 
*/
@Effect() OnIdentityAuthorized$ = this._actions.ofType(ON_IDENTITY_AUTHORIZED)
  .switchMap(identity => this._subscriptionActions.ListSubscriptions(identity))

Obviously, would still love to have someone with more experience with the @Effects pattern on medium/large projects chime in.

Upvotes: 1

Related Questions