Angular(v21)에서 Effects와 InjectionContext

발행: (2026년 2월 1일 오전 04:42 GMT+9)
4 min read
원문: Dev.to

Source: Dev.to

The Injector: The “Source of Truth”

Injector는 서비스와 의존성 인스턴스를 보관하는 컨테이너입니다. Angular에서는 Injector 계층 구조(환경 Injector, 컴포넌트 Injector 등)가 존재합니다.

effect를 생성할 때, 그것은 Injector에 고정되어야 합니다. Injector는 effect가 필요로 할 수 있는 서비스들을 제공하고, 더 중요한 것은 effect의 수명을 결정합니다.

Injection Context: The “Where” and “When”

Injection Context는 inject() 함수가 사용 가능한 코드 실행 중의 특정 상태를 의미합니다. 객체(컴포넌트, 디렉티브 등)가 생성되는 기간이라고 생각하면 됩니다.

기본적으로 Injection Context는 다음에서 사용할 수 있습니다:

  • 클래스의 생성자.
  • 필드 초기화(예: myService = inject(MyService)).
  • Provider의 팩토리 함수.

Why does an effect need it?

생성자에서 effect(() => { … })를 호출하면, Angular는 현재 Injection Context를 암묵적으로 찾아 DestroyRef를 “주입”합니다. 이를 통해 effect를 언제 “종료”해야 하는지 정확히 파악하여 메모리 누수를 방지합니다.

The inject() Function: The Modern Fetcher

inject() 함수는 현재 Injection Context에서 의존성을 프로그래밍적으로 가져오는 방법입니다.

일반 메서드(예: 버튼 클릭) 내부에서 effect를 만들려고 하면, 해당 메서드에는 Injection Context가 없기 때문에 실패합니다.

// ✅ WORKS: In the constructor / class init
count = signal(0);
myEffect = effect(() => console.log(this.count()));

// ❌ FAILS: Outside injection context
updateData() {
  effect(() => { /* … */ }); // Error: inject() must be called from an injection context
}

Capturing the injector manually

export class MyComponent {
  private injector = inject(Injector); // Capture the injector in the constructor

  startManualEffect() {
    // Pass the captured injector to the effect
    effect(() => {
      console.log('Manual effect running!');
    }, { injector: this.injector });
  }
}

DestroyRef: The “Clean‑up Crew”

DestroyRefOnDestroy 라이프사이클 훅의 현대적인 대체물입니다. 클래스 정의에만 국한되지 않고 코드 어디에서든 정리 로직을 등록할 수 있게 해줍니다.

effect가 생성될 때, 내부적으로 해당 컨텍스트의 DestroyRef에 구독합니다. 그 effect를 보유한 컴포넌트나 서비스가 파괴되면 DestroyRef가 발동하고 effect가 자동으로 중지됩니다.

Manual cleanup with DestroyRef

const dr = inject(DestroyRef);
const sub = mySignal.subscribe(...);

dr.onDestroy(() => {
  console.log('Cleaning up resources!');
  sub.unsubscribe();
});

The runInInjectionContext Helper

때때로 Injector가 있지만 매 함수에 옵션으로 전달하고 싶지 않을 때가 있습니다. 컨텍스트를 “강제”할 수 있습니다:

import { runInInjectionContext } from '@angular/core';

runInInjectionContext(this.injector, () => {
  // Anything called here now has access to inject()
  effect(() => console.log('I have context!'));
});

Code Playground

Key Points to Remember

  • EffectsInjector에 연결됩니다.
  • InjectorsDestroyRef를 사용해 정리합니다.
  • inject()는 Injection Context가 활성화된 경우에만 작동합니다.
  • 생성자 외부에서 effect를 만들 경우, Injector를 수동으로 제공해야 합니다.

Happy coding!

Back to Blog

관련 글

더 보기 »

Angular i18n에서 누락된 조각

앱이 변경될 때마다 번역이 깨지는 것을 방지하는 방법은 Angular의 i18n 스토리가 처음에는 완전해 보이지만, 실제로는 그렇지 않다는 점을 이해하는 것입니다. 문자열에 마크를 하고, `ng extract-i18n`를 실행하고, …

Claude Code Custom Agent 설계 여정: Agent 중심에서 Task 중심으로

들어가며 Design Doc 작성을 자동화하고 싶었다. 디자인 시안을 확인하고, 기획서를 읽고, 코드베이스를 파악해서 초안을 뽑아주는 것이 /design-doc Command의 목표였다. Command는 금방 만들었지만, 그 다음 단계인 Custom Agent 설계가 문제였다. 두 번...