rxjs operators 그리고 bind this context
📄

rxjs operators 그리고 bind this context

Created
Nov 28, 2021 12:51 PM
Tags
rxjs
js
issue
(1)
rxjs를 사용하며 이슈가 하나 있었다.
this 컨텍스트를 바인딩하면 operators가 정상적으로 동작하지 않는다는 것.
코드를 보면 이렇다.
 
const { BehaviorSubject, operators } = rxjs;
const { pairwise } = operators;

const subject = new BehaviorSubject(0);

// expected: "[0, 1]", and got the same result
subject.pipe(pairwise()).subscribe(console.log);

const bindedSubscribe = subject
	.pipe(pairwise())
  .subscribe.bind(subject);

// expected: "[0, 1]", but output "0" and "1"
bindedSubscribe(console.log);

subject.next(1);

// this also gives same result
// subject.next.bind(subject)(1);
 
(2)
이슈를 남기기 전 기존에 이런 문제점이 언급되지 않았나 찾아보았었다.
물론 유사한 이슈가 존재했고, 내가 제대로 이해했다면 위 방법은 정석이 아니라는 것을 알게 되었다.
 
notion image
 
Subscriber의 Context Binding은 rxjs의 목표가 아니라는 것.
그래서 그냥 이슈를 남기지 않고 기존 bind 했던 것을 고쳐주었다.
 
(3)
바뀐 코드는 이렇다.
 
import { State } from 'src/types/store';
import { BehaviorSubject, pairwise } from 'rxjs';

const state: State = {
  contents: [],
};

const createStore = <T>(
  state: T,
): { [K in keyof T]: BehaviorSubject<T[K]> } => {
  const store: any = {};

  for (const key in state) {
    store[key] = new BehaviorSubject(state[key]);
  }

  return store;
};

export const store = createStore(state);

type StateKeys = keyof State;
type BehaviorSubjectOfState<K extends StateKeys> = BehaviorSubject<State[K]>;

const getSubject = <K extends StateKeys>(key: K) =>
  store[key] as unknown as BehaviorSubjectOfState<K>;

export const setState =
  <K extends StateKeys>(key: K) =>
  (value: State[K]) =>
    getSubject(key).next(value);

export const subscribe =
  <K extends StateKeys>(key: K) =>
  (next: (value: [State[K], State[K]]) => void) =>
    getSubject(key).pipe(pairwise()).subscribe(next);

/* usage */

setState('contents')(/* next contents */);
subscribe('contents')(
  ([prevContents, nextContents]) =>
    console.log({ prevContents, nextContents }));
 
기존 코드는 이랬다.
 
import { State } from 'src/types/store';
import { BehaviorSubject, pairwise } from 'rxjs';

const state: State = {
  contents: [],
};

const createStore = <T>(
  state: T,
): { [K in keyof T]: BehaviorSubject<T[K]> } => {
  const store: any = {};

  for (const key in state) {
    store[key] = new BehaviorSubject(state[key]);
  }

  return store;
};

export const store = createStore(state);

type StateKeys = keyof State;
type BehaviorSubjectOfState<K extends StateKeys> = BehaviorSubject<State[K]>;

const getSubject = <K extends StateKeys>(key: K) =>
  store[key] as unknown as BehaviorSubjectOfState<K>;

export const setState = <K extends StateKeys>(key: K) =>
  getSubject(key).next.bind(store[key]);

export const subscribe = <K extends StateKeys>(key: K) =>
  getSubject(key).pipe(pairwise()).subscribe.bind(store[key]);

/* usage */

setState('contents')(/* next contents */);

// not available
subscribe('contents')(
  ([prevContents, nextContents]) =>
    console.log({ prevContents, nextContents }));
 
setStatesubscribe 에 더 이상 bind 를 사용하지 않도록 고쳐주었다.
 
(0)
references
 

Loading Comments...