composables.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import {
  2. customRef,
  3. DeepReadonly,
  4. onBeforeUnmount,
  5. readonly,
  6. Ref,
  7. ref,
  8. watch,
  9. wrapProperty,
  10. } from "@nuxtjs/composition-api"
  11. import { Observable, Subscription } from "rxjs"
  12. export const useNuxt = wrapProperty("$nuxt")
  13. export function useReadonlyStream<T>(
  14. stream$: Observable<T>,
  15. initialValue: T
  16. ): Ref<DeepReadonly<T>> {
  17. let sub: Subscription | null = null
  18. onBeforeUnmount(() => {
  19. if (sub) {
  20. sub.unsubscribe()
  21. }
  22. })
  23. const targetRef = ref(initialValue) as Ref<T>
  24. sub = stream$.subscribe((value) => {
  25. targetRef.value = value
  26. })
  27. return readonly(targetRef)
  28. }
  29. export function useStream<T>(
  30. stream$: Observable<T>,
  31. initialValue: T,
  32. setter: (val: T) => void
  33. ) {
  34. let sub: Subscription | null = null
  35. onBeforeUnmount(() => {
  36. if (sub) {
  37. sub.unsubscribe()
  38. }
  39. })
  40. return customRef((track, trigger) => {
  41. let value = initialValue
  42. sub = stream$.subscribe((val) => {
  43. value = val
  44. trigger()
  45. })
  46. return {
  47. get() {
  48. track()
  49. return value
  50. },
  51. set(value: T) {
  52. trigger()
  53. setter(value)
  54. },
  55. }
  56. })
  57. }
  58. export function pluckRef<T, K extends keyof T>(ref: Ref<T>, key: K): Ref<T[K]> {
  59. return customRef((track, trigger) => {
  60. const stopWatching = watch(ref, (newVal, oldVal) => {
  61. if (newVal[key] !== oldVal[key]) {
  62. trigger()
  63. }
  64. })
  65. onBeforeUnmount(() => {
  66. stopWatching()
  67. })
  68. return {
  69. get() {
  70. track()
  71. return ref.value[key]
  72. },
  73. set(value: T[K]) {
  74. trigger()
  75. ref.value = Object.assign(ref.value, { [key]: value })
  76. },
  77. }
  78. })
  79. }
  80. export function pluckMultipleFromRef<T, K extends Array<keyof T>>(
  81. sourceRef: Ref<T>,
  82. keys: K
  83. ): { [key in K[number]]: Ref<T[key]> } {
  84. return Object.fromEntries(keys.map((x) => [x, pluckRef(sourceRef, x)])) as any
  85. }
  86. /**
  87. * A composable that provides the ability to run streams
  88. * and subscribe to them and respect the component lifecycle.
  89. */
  90. export function useStreamSubscriber() {
  91. const subs: Subscription[] = []
  92. const runAndSubscribe = <T>(
  93. stream: Observable<T>,
  94. next?: (value: T) => void,
  95. error?: (e: any) => void,
  96. complete?: () => void
  97. ) => {
  98. const sub = stream.subscribe({
  99. next,
  100. error,
  101. complete: () => {
  102. if (complete) complete()
  103. subs.splice(subs.indexOf(sub), 1)
  104. },
  105. })
  106. subs.push(sub)
  107. }
  108. onBeforeUnmount(() => {
  109. subs.forEach((sub) => sub.unsubscribe())
  110. })
  111. return {
  112. subscribeToStream: runAndSubscribe,
  113. }
  114. }