Skip to content

Allow lifecycle hooks to be defined on a directive instance and not only on a prototype #38241

Open

Description

@pkozlowski-opensource

We tend to get repeated requests for Angular to invoke lifecycle hooks defined on a directive / component instance (and not only ones defined on a prototype). Examples of such requests (actually, reported as bugs) would be #38043 or #38087 (but I'm sure that there are more as I've seen similar issues reported in the past.

To start with, the current Angular behaviour is the result of deliberate design choices and not a simple bug / omission that we can "just fix". The current design of taking lifecycle hooks from a prototype is based on the following:

  • performance considerations;
  • inheritance support.

Performance considerations

As of today Angular assumes that all directives created from a given class have the same set of lifecycle functions (taken from a prototype). This assumptions allows us to make 2 significant optimisations:

  • store lifecycle hooks only once for a given directive class, regardless of how many times it is instantiated (imagine a ngFor loop over hundreds of components / directives - as of today we need to store info about lifecycle hooks only one, regardless of the number of instances - if each instance could have different lifecycle hooks we would have to allocate memory for each instance, adding to GC pressure, consuming more memory and making the app slower overall);
  • invoke lifecycle hooks on all instances without worrying about checking if a given hook exists - basically we know that all components / directives share the same set so we can iterate over all instances and call hooks, without doing any checks.

Those things might sound like micr-optimisations but when you profile applications it has significant impact. Angular always worked this way as we made the assumption that the user experience (performance of a final app for the users) is more important that the developers experience here.

Inheritance

With the assumptions of a fixed set of lifecycle hooks for a directive it is easy for us to compute a new set of lifecycle hooks in the directives inheritance tree. Again, we can do those calculations only once (per directive class), without checking each individual instance.

Possible work-arrounds

@petebacondarwin suggested that one might work-arround the current design choices like so:

@Component({selector: 'app-root', template: ''})
export class AppComponent {
  title = 'test-app';
}

(AppComponent.prototype as any).ngOnInit = () => {
  console.log('init!');
};

I'm opening this issue as a feature request, mostly to track interest and ideas for another implementation that wouldn't negatively impact performance.

Activity

  1. added this to the Backlog milestone on Jul 27, 2020
  2. petebacondarwin commented on Jul 27, 2020

    @petebacondarwin
    Contributor

    Another versatile workaround, but that would incur a localized performance loss just for that component, is to define the lifecycle hook as normal on the prototype but for that method to delegate to a private method you you can indeed change per instance.

  3. VagrantAI-c commented on Aug 20, 2020

    @VagrantAI-c

    Might offer a few possibilities:

    • looking at common lifecycle overwrite use-cases, unsubscribing would be the most used one. What if Angular team introduce rxjs operator like takeUntilDestroyed(this) which would unsubscribe specified pipeline upon ngOnDestroy call automatically on Angular behalf, since app might know when and for whom it calls lifecycle hooks.
    • maybe a globar helper function might come in handy, like overrideOnDestroy<T>(targetComponent: Type<T>, callbackFn: () => void) or enrichOnDestroy with similar declaration just for programmatical enrichment of lifecycle hooks. Since this is a pretty uncommon use-case, one who attempts to meddle with lifecycle hook might research this approach, and others would live happily with optimised hooks.

    I don't know lifecycle architecture, so these above are just thoughts and assumptions: can't say at all whether it is possible to implement or is consistent with Angular approach.

  4. added
    P3An issue that is relevant to core functions, but does not impede progress. Important, but not urgent
    on Oct 19, 2020
  5. arturovt commented on Sep 29, 2026

    @arturovt
    Contributor

    @JeanMeche this can be closed. The report itself states the reason the current design exists: hook metadata is computed once per class, so instance hooks would mean per-instance bookkeeping and per-instance inheritance walks on a hot path, for every directive in every app.

    It was filed to gauge community interest, and six years later there is none: no upvotes, no comments, no duplicates beyond the two reports that prompted it. That answers the question it was opened to ask.

    The prototype assignment noted in the report covers the rare case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3An issue that is relevant to core functions, but does not impede progress. Important, but not urgentarea: coreIssues related to the framework runtimecore: lifecycle hooksfeatureLabel used to distinguish feature request from other issues

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions