DEV Community

loading...
Cover image for Rx Composition Api [Vue 3 | RxJS]

Rx Composition Api [Vue 3 | RxJS]

noprod profile image NOPROD ☄️ Updated on ・2 min read

edit: you can use this package i made https://www.npmjs.com/package/@nopr3d/rx-vue-next

Hi !

Vue 3 is here, is fresh but we have to wait for our preferred dependences.

So vue-rx work only with Vue 2 and I think you are wondering how we can use rxjs with the new version of vue? (I'm)


So, this is how we can extend the composition Api

Ref
import { Observer, Observable, Subject } from "rxjs";
import { onBeforeUnmount, ref as _ref, Ref as _Ref, watch } from "vue";

export type Ref<T = any> = _Ref<T> & Observer<T> & Observable<T>;

export function ref(value?: unknown): Ref {
  const $ref = _ref(value) as Ref;
  const subject = new Subject();

  // extend your ref to rx and bind context
  $ref.next = subject.next.bind(subject);
  $ref.pipe = subject.pipe.bind(subject);
  $ref.subscribe = subject.subscribe.bind(subject);



  watch($ref, (val) => {
    subject.next(val);
  });

  // Don't forget to unsubscribe or you will get memory leaks
  onBeforeUnmount(() => subject.unsubscribe()); 
  return $ref;
}
Enter fullscreen mode Exit fullscreen mode

Watch
import {
  watch as _watch,
  WatchStopHandle as _WatchStopHandle,
} from "vue";

export type WatchStopHandle<T = any> = Observer<T> &
  Observable<T> &
  (() => void);

export function watch(ref: Ref, fn?: (val: any) => any): WatchStopHandle {

  const subject = new Subject();
  const $watch = _watch(ref, (val) => {
    subject.next(val);
    if (fn) fn(val);
  }) as WatchStopHandle;

  $watch.next = subject.next.bind(subject);
  $watch.pipe = subject.pipe.bind(subject);
  $watch.subscribe = subject.subscribe.bind(subject);

  onBeforeUnmount(() => subject.unsubscribe());

  return $watch;
}
Enter fullscreen mode Exit fullscreen mode

So we can use the return of our composition function like any usual observable.

// Create your own vue folder, store your custom api here
import { ref, watch } from "@/vue";

export default {
  name: "App",
  setup() {
    const tick = ref(0);

    setInterval(() => {
      tick.value++;
    }, 1000);

    // subscribe and do something at every change

    // With Ref
    tick.subscribe((value)=>{console.log(value)}); 

   // With Watch
    watch(tick)
        .pipe(map((val) => val * 1000))
        .subscribe(console.log);

    return { tick };
  },
};

Enter fullscreen mode Exit fullscreen mode

Demo :

Wanna more about RxJs ? You can read this RxJs in Practice

Discussion

pic
Editor guide
Collapse
oceangravity profile image
Collapse
noprod profile image