pub/sub 이 필요한 경우. rx의 relay 부분만 따로 구현.
Relay.ts
export class Relay<T> {
private _current: T;
private subscribers: Set<(value: T) => void> = new Set();
private disposeBag = new DisposeBag();
private constructor(value: T) {
this._current = value;
}
static create<T>(value: T) {
return new Relay(value);
}
map<U>(transform: (value: T) => U): Relay<U> {
const relay = Relay.create(transform(this._current));
this.subscribe((value) => (relay.current = transform(value))).disposedBy(
this.disposeBag,
);
return relay;
}
flatMap<U>(transform: (value: T) => Relay<U>): Relay<U> {
const relay = transform(this._current);
this.subscribe((value) => {
transform(value).subscribe((value) => (relay.current = value));
}).disposedBy(this.disposeBag);
return relay;
}
bind(relay: Relay<T>) {
return this.subscribe((value) => (relay.current = value));
}
subscribe(callback: (value: T) => void): Disposable {
this.subscribers.add(callback);
callback(this._current);
return new Disposable(() => {
this.disposeBag.dispose();
this.subscribers.delete(callback);
});
}
private reportToSubscribers() {
this.subscribers.forEach((callback) => callback(this._current));
}
set current(value: T) {
this._current = value;
this.reportToSubscribers();
}
get current() {
return this._current;
}
}
DisposeBag.ts
export class Disposable {
private disposeJob: () => void = () => {};
constructor(jbo: () => void) {
this.disposeJob = jbo;
}
dispose() {
this.disposeJob();
this.disposeJob = () => {};
}
disposedBy(bag: DisposeBag) {
bag.add(this);
}
}
export class DisposeBag {
private disposables: Disposable[] = [];
add(disposable: Disposable) {
this.disposables.push(disposable);
}
dispose() {
this.disposables.forEach((disposable) => {
disposable.dispose();
});
this.disposables = [];
}
}
useDisposeBag.ts
export const useDisposeBag = () => {
const disposeBag = useRef(new DisposeBag());
useEffect(() => {
const bag = disposeBag.current;
return () => bag.dispose();
}, []);
return disposeBag.current;
};