web-dev-qa-db-ja.com

rxjs5でオブジェクトの変更を監視する方法

オブジェクトを監視したいので、すべてのサブスクライバーにオブジェクトの変更が通知されます。

私はそれがすでに 前に尋ねられた であるのを見ました、それでもRXjsバージョン5はそのAPIにofObjectChangesを含まないので答えは無関係ですもう。

関数を返すオブザーバーを作成するような「ハック」をいくつか見てきました。

let myObservable =  new Observable((observer) => {
  return (data) => {
    observer.next(data)
  }
}) 
//...
myObservable.subscribe()('someData')

しかし、もっとエレガントな方法があると確信しています。何か案は?

8
yuval.bl
0
Vamshi

オブジェクトを監視するES6の方法は、 プロキシ を使用することです。元のオブジェクトをラップするプロキシを作成し、それに対して作業を行います。これを使用して、Observable.ofObjectChangesに似たものを作成できます。ここでは部分的な実装(setのみ。他の traps を実装する必要があります):

Observable.ofProxyChanges = (target) => {
  let subject = new Subject
  let proxy = new Proxy(target, {
    set(target, key, val) {
      let oldValue = target[key]
      target[key] = val
      subject.next({
        type: oldValue === undefined ? "add" : "change",
        object: target,
        name: key,
        oldValue: oldValue
      })
    }
  })
  return [proxy, subject.asObservable()]
}

let [obj, objChange$] = Observable.ofProxyChanges({})
objChange$.subscribe(console.log)

obj.bar = 1 // logs { type: "add", name: "bar", object: { bar: 1 } }
obj.foo = 2 // logs { type: "add", name: "foo", object: { bar: 1, foo: 2 } }
obj.foo = 3 // logs { type: "change", name: "foo", object: { bar: 1, foo: 3 }, oldValue: 2 }
6

オブジェクトに事前定義された方法で変更を加えることができる場合は、reduxアプローチに似たものを使用することをお勧めします。

function factory(reducerByType, initialState) {
  const action$ = new Rx.Subject();
  const state$ = action$
    .startWith(initialState)
    .scan((state, action) => {
      if (reducerByType.hasOwnProperty(action.type)) {
        return reducerByType[action.type](state, action);
      }
      
      return state;
    })
    .distinctUntilChanged();
  
  
  return {
    action$,
    state$,
    dispatch: action => action$.next(action)
  }
}

const {state$, dispatch} = factory({
  ADD: (state, action) =>  state + action.number,
  SUBTRACT: (state, action) =>  state - action.number,
}, 0);

state$.subscribe(val => console.log(val));

dispatch({
  type: 'ADD',
  number: 10,
});

dispatch({
  type: 'SUBTRACT',
  number: 15,
});

dispatch({
  type: 'SUBTRACT',
  number: 0,
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.0/Rx.js"></script>
3
Lukas Neicelis