ilokesto

Angular 연동

Angular adapter는 injection context 또는 명시적인 DestroyRef로 cleanup을 제공할 수 있는 위치에서 사용하세요. @ilokesto/state/angular에서 import합니다.

Plain state signal

import { Component, DestroyRef, inject } from '@angular/core';
import { create } from '@ilokesto/state/angular';

const useCounter = create({ count: 0, label: 'Clicks' });

@Component({ selector: 'counter-view', template: `<button (click)="inc()">{{ label() }}: {{ count() }}</button>` })
export class CounterView {
  private destroyRef = inject(DestroyRef);
  private countResult = useCounter((state) => state.count, { destroyRef: this.destroyRef });
  private labelResult = useCounter((state) => state.label, { destroyRef: this.destroyRef });

  count = this.countResult.state;
  label = this.labelResult.state;
  inc = () => this.countResult.setState((state) => ({ ...state, count: state.count + 1 }));
}

plain state는 { state: Signal<S>, setState, subscribe }를 반환합니다.

Reducer signal

import { create } from '@ilokesto/state/angular';

type Action = { type: 'increment' } | { type: 'reset' };

const reduce = (state: { count: number }, action: Action) => {
  if (action.type === 'increment') return { count: state.count + 1 };
  if (action.type === 'reset') return { count: 0 };
  return state;
};

const useCounter = create(reduce, { count: 0 });

export class ReducerCounter {
  private result = useCounter((state) => state.count);
  count = this.result.state;
  increment = () => this.result.dispatch({ type: 'increment' });
}

Angular 생명주기 밖에서 사용하기

const count = useCounter.readOnly((state) => state.count);
const dispatch = useCounter.writeOnly();
dispatch({ type: 'reset' });

주의할 점

  • { destroyRef }가 없으면 adapter는 inject(DestroyRef)를 호출하므로 injection context가 필요합니다.
  • cleanup은 destroyRef.onDestroy(unsubscribe)에 등록됩니다.
  • adapter result는 low-level integration을 위해 subscribe도 노출하지만 template에서는 signal을 우선 사용하세요.

목차