Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(effects): add OnIdentifyEffects interface to register multiple effect instances #1448

Merged
merged 2 commits into from
Dec 4, 2018

Conversation

timdeschryver
Copy link
Member

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the current behavior?

Closes #1443

What is the new behavior?

This change reverts #1249 in order to only instantiate effects once (e.g. when imported in different features).
This PR adds a way to identify effects while using the addEffects method in order to resolve #1246.

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

@brandonroberts
Copy link
Member

What do you think about making the identifier something that is pulled from the effect? Like a lifecycle method that is called from the effect instance in the groupBy if present? I'd like something more defined for the identifier.

@timdeschryver
Copy link
Member Author

I think that should also work, something like this right?

export class FooEffects implements EffectIdentifier {
  identifier = 'Foo';
}

@brandonroberts
Copy link
Member

Yep

@timdeschryver timdeschryver force-pushed the pr/effect-sources-identifier branch from 684117e to 4c96ffc Compare November 29, 2018 16:05
@coveralls
Copy link

coveralls commented Nov 29, 2018

Coverage Status

Coverage remained the same at 88.342% when pulling 3a6d41f on pr/effect-sources-identifier into 6a754aa on master.

@timdeschryver timdeschryver force-pushed the pr/effect-sources-identifier branch from 4c96ffc to 099f5e3 Compare November 29, 2018 16:06
@dummdidumm
Copy link
Contributor

I think different effect classes should be able to get instantiated even if they have the same identifier.
So if class EffectsA has identifier "abc" and EffectsB also has identifier "abc", they should both get instantiated. With the current implementation this is not the case I think.

@dummdidumm
Copy link
Contributor

I also think that getting the identifier from the class instance is not a good idea. People now have to know that "identifier" is a reserved property that the effects library uses. If someone does not implement the interface but still uses a variable called identifier for something else, strange things could happen.

@timdeschryver
Copy link
Member Author

@dummdidumm I agree with:

I think different effect classes should be able to get instantiated even if they have the same identifier.
So if class EffectsA has identifier "abc" and EffectsB also has identifier "abc", they should both get instantiated. With the current implementation this is not the case I think.

I think identifier is perhaps a bit too general, ngrxIdentifier or effectIdentifier might be better.

@timdeschryver
Copy link
Member Author

@dummdidumm Why should it be a,a,b,b?

@dummdidumm
Copy link
Contributor

dummdidumm commented Nov 30, 2018

SourceWithIdentifier is instantiated with identifier, "a" two times, SourceWithIdentifier 2 is instantiated with identifier "b" two times . It should be "a","b" for each effect class. Then all four should get instantiated.

@timdeschryver
Copy link
Member Author

You're right, it behaves that way but the test didn't match the description.

@@ -0,0 +1,6 @@
export interface EffectIdentifier {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need some more doc here for the API page 😉

/**
 * @description 
 * Interface to set an identifier for effect instances.
 * 
 * By default, each Effects class will only be registered
 * once regardless of how many times the Effect class
 * is loaded. By implementing this interface, you define
 * a unique identifier to register an Effects class instance
 * multiple times.
 * 
 * @usageNotes
 * 
 * ### Set an identifier for an Effects class
 * 
 * ```
 * Example code here
 * ```
 */
export interface EffectIdentifier {
  /**
   * @description
   * String identifier to differentiate effect instances.
   */
  effectIdentifier: string;
}

@dummdidumm
Copy link
Contributor

dummdidumm commented Nov 30, 2018

I still think that setting the identifier on the class is not the best possible solution.

  • people could use a property of the same name in a different context without knowing and get strange results
  • angular's dependency injection needs to know where the constructor property comes from. So you cannot provide that effect class to the effectsmodule through forFeature/forRoot without workarounds
  • in my opinion conceptually it is not the responsibility of the class itself to know "who it is". The addEffects function should know that instead.

What are your arguments against going with the initial proposal ?

@timdeschryver
Copy link
Member Author

I don't have a favorite way of solving this (the first proposal vs the interface).

You're right with your second point @dummdidumm , but I'm not quite agreeing with your first point. Angular does more or less do the same with their lifecycle hooks, plus it opens up opportunities to introduce more of these in NgRx e.g. in #1447.

@dummdidumm
Copy link
Contributor

dummdidumm commented Dec 1, 2018

You are right, it opens up more possibilities, and yeah, angular does kind of the same, so I'm fine with it I guess. Regarding the API: Maybe we should decide on a prefix (like angular did with their lifecycle hooks with "ng"). "ngrx" would seem like a natural fit.
There is also "ngrxOnRunEffects" already which would be one more argument towards going with the interface approach.

@timdeschryver
Copy link
Member Author

I forgot about ngrxOnRunEffects for a second 😅 .

To stay consistent I would want to rename the property effectIdentifier to ngrxEffectIdentifier and also move the OnRunEffects interface to the lifecycle_hooks, would that be OK @brandonroberts ?

@brandonroberts
Copy link
Member

@timdeschryver that's fine with me because it doesn't change the public API. I'd rather see this implemented as a method if we're being similar to ngrxOnRunEffects and have it be ngrxOnIdentify which is a little more descriptive.

@timdeschryver
Copy link
Member Author

👍 I'll implement it the way you suggested.
Thanks for the feedback @dummdidumm and @brandonroberts !

@timdeschryver
Copy link
Member Author

What about ngrxOnIdentifyEffects (sorry, I know that I'm annoying 😅 )?

@brandonroberts
Copy link
Member

brandonroberts commented Dec 3, 2018

😂

That's fine. You're identifying this set of effects 👍

@timdeschryver timdeschryver force-pushed the pr/effect-sources-identifier branch 3 times, most recently from 1f1170b to c0feb45 Compare December 3, 2018 19:45
@@ -47,3 +55,34 @@ export class EffectSources extends Subject<any> {
);
}
}

function effectsInstance(source: any) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function effectsInstance(source: any) {
function effectsInstance(sourceInstance: any) {

* @description
* Interface to set an identifier for effect instances.
*
* By default, each Effects class will only be registered
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* By default, each Effects class will only be registered
* By default, each Effects class is registered

@@ -84,6 +84,12 @@ export class MyEffects {
}
```

### reserved property `ngrxOnIdentifyEffects`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be in the migration doc as it doesn't break existing behavior. We should update the PR to a feat that adds the ngrxOnIdentifyEffects interface.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason why I added it to the migration is that if someone would already use this property. But the chance that this is the case is probably zero.

export { EffectNotification } from './effect_notification';
export { ROOT_EFFECTS_INIT } from './effects_root_module';
export { UPDATE_EFFECTS, UpdateEffects } from './effects_feature_module';
export {
OnIdentifyEffects,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be sufficient to only export the interfaces publicly

@brandonroberts brandonroberts changed the title fix(Effects): instantiate effect once when used in multiple features feat(effects): add OnIdentifyEffects interface to register multiple effect instances Dec 3, 2018
@timdeschryver timdeschryver force-pushed the pr/effect-sources-identifier branch from c0feb45 to 3a6d41f Compare December 3, 2018 20:42
@brandonroberts
Copy link
Member

@timdeschryver one more minor nit. Will you fix the first commit message with OnIdentifyEffects. It currently says OnIdentityEffects. I'm going to land the commits as-is.

@timdeschryver timdeschryver force-pushed the pr/effect-sources-identifier branch from 3a6d41f to 8980112 Compare December 4, 2018 06:47
@brandonroberts brandonroberts merged commit b553ce7 into master Dec 4, 2018
@brandonroberts brandonroberts deleted the pr/effect-sources-identifier branch December 4, 2018 13:19
@timdeschryver timdeschryver restored the pr/effect-sources-identifier branch March 27, 2019 21:35
@timdeschryver timdeschryver deleted the pr/effect-sources-identifier branch March 27, 2019 21:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
4 participants