-
Notifications
You must be signed in to change notification settings - Fork 190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vue Composition API and vue-rx #120
Comments
It should be trivial to write a composition function like As for DOM event streams, something like this should also be doable: setup() {
const { handler: inc, stream: inc$ } = useDOMStream('click')
const count = useObservable(inc$.pipe(
map(() => 1),
startWith(0),
scan((total, change) => total + change)
))
return {
count,
inc
}
} |
Ran across this thread thinking through the integration of rxjs. Only issue seems to be the initial value of the ref in both Observable and BehaviorSubject situations. Not sure what the best way to handle this. Use vue2 comp api plugin so readonly isn't available as a function hence the use of computed.
|
I also came across this thread a few months ago and after testing various approaches, I finally settled on the approach below. I wanted to keep the registration of subscription at the component level to ensure proper unsubscribing (as it is done currently). For the v-stream part, initially I thought about keeping the directive, but it's actually really trivial to emulate the main functionality (not all use cases I'm sure) for a slight cost in syntax heaviness (but for a greatly simplified implementation also). The useDOMStream function below returns both the "plus$" stream and the "plus" callback (that simply pushes event values down to the "plus$" stream). If you want a reference, you just chain the useObservable function (see example below). Usage is as follows: <template lang="pug">
button(@click="plus")
br
pre {{ count }}
</> import Vue from 'vue';
import { ref, reactive } from '@vue/composition-api';
import { useObservable, useDOMEvent } from 'composables/observables';
import { startWith } from 'rxjs/operators';
export default Vue.extend({
setup() {
const { subject: plus$, callback: plus } = useDOMEvent();
const count = useObservable(plus$.pipe(
map(() => 1),
startWith(0),
scan((total, change) => total + change)
))
return {
count,
plus
} Implementation: import { ref, Ref, onBeforeUnmount } from '@vue/composition-api';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
function subscribeTo<T>(
observable: Observable<T>,
next?: (value: T) => void,
error?: (err: any) => void,
complete?: () => void
) {
const unsubscribe$ = new Subject<void>();
const subscription = observable
.pipe(takeUntil(unsubscribe$))
.subscribe(next, error, complete);
onBeforeUnmount(() => {
unsubscribe$.next();
unsubscribe$.complete();
});
return subscription;
}
export function useObservable<T>(
observable: Observable<T>,
defaultValue?: T
): Ref<T> {
const handler = ref(defaultValue) as Ref<T>;
subscribeTo(
observable,
value => {
handler.value = value;
},
error => {
throw error;
}
);
return handler;
}
export function useSubscription<T>(
observable: Observable<T>,
next?: (value: T) => void,
error?: (err: any) => void,
complete?: () => void
) {
return subscribeTo(observable, next, error, complete);
}
export function useDOMEvent() {
const subject = new Subject();
return {
subject,
callback: (event: Event) => {
subject.next(event);
}
};
} |
When subject catch an error in the pipe stream, this subject would fail to work any more!
maybe v-stream part is still important |
function subscribeTo<T>(
observable: Observable<T>,
next?: (value: T) => void,
error?: (err: any) => void,
complete?: () => void
) {
const unsubscribe$ = new Subject<void>();
const subscription = observable
.pipe(takeUntil(unsubscribe$))
.subscribe(next, error, complete);
onBeforeUnmount(() => {
unsubscribe$.next();
unsubscribe$.complete();
});
return subscription;
} Why not: function subscribeTo<T>(
observable: Observable<T>,
next?: (value: T) => void,
error?: (err: any) => void,
complete?: () => void
) {
const subscription = observable
.subscribe(next, error, complete);
onBeforeUnmount(() => {
subscription.unsubscribe();
});
return subscription;
} |
@kevin-courbet can be also a wrapper from util setup() {
const page = ref(0)
const products = ref([])
const text = from(page).pipe(map(x => 'page: ' + x)) // can work like watch or computed, this lib provide from
from(page).pipe(filter(x => x > 0 && x < 10), fetchProducts()).subscribe(products)
return {
count,
double,
products
}
} or extend ref to implement Observer and Observable interface export const count = ref(0)
count.pipe(map(count => count * 2)).subscribe(c => console.log(c)) pseudo implementation import { Observer, Observable } from "rxjs";
import { ref as R, Ref as Rf } from 'vue';
type Ref<T = any> = Rf<T> & Observer<T> & Observable<T>
// and something like
export function ref(value?: unknown): Ref {
const or = R(value) as Ref
const beha = new Subject()
or.next = beha.next.bind(beha)
or.pipe = beha.pipe.bind(beha)
or.subscribe = beha.subscribe.bind(beha)
watch(or, val => beha.next(val))
onBeforeUnmount(() => beha.unsubscribe())
return or
} with this vue reactive system become compatible with rxjs |
@mdbetancourt Thanks for the tips, i started with your advice for the implementation @ebeloded feel free to try it if you need : https://github.com/NOPR9D/vue-next-rx |
Should we use separate library like |
you can use https://github.com/antfu/vue-demi |
use watcheffect on any ref |
How would useObservable handle unsubscribe when the component is destroyed? |
It should, it is, and it has been done. For all who come to this project looking for a way to use RxJS @yyx990803 maybe it would make sense to officially deprecate this project, especially now that Vue 2 is no longer maintained? We could add a deprecation notice to the README with a recommendation to use VueUse. This would potentially resolve #148 and #152 as well. |
As the launch day of Vue 3.0 with composition API is approaching, it's worth discussing how
vue-rx
will fit into the new paradigm.My understanding is that one can only rely on options API to use
vue-rx
. Is there a composition alternative in the works?The text was updated successfully, but these errors were encountered: