When integrating with Angular’s DI and reactivity, follow these rules:
effect(...) to keep signals in sync, add/propagate cleanup via the effect onCleanup argument wherever long-lived listeners/subscriptions are created.allowSignalWrites: true and wrap option reads in untracked when needed to avoid unintended tracking loops.withInterceptors(...) over DI-provided interceptor classes. Also avoid redundant HttpClientModule wiring when using provideHttpClient(...).Example pattern for effect-driven signal updates:
import { DestroyRef, effect, inject, signal, untracked, type Injector } from '@angular/core';
export function injectSomething(optionsFn = () => ({}), injector?: Injector) {
// resolve dependencies from injector / injection context here
return ((): any => {
const destroyRef = inject(DestroyRef);
const value = signal(0);
effect(
() => {
const opts = untracked(() => optionsFn());
// imperative signal update inside effect
value.set(opts.someValue);
},
{ allowSignalWrites: true }
);
return value;
})();
}
Applying this set of practices will make utilities safer to use across injection contexts, reduce lifecycle leaks, and align with Angular’s current HTTP interceptor direction.