Skip to content

Commit

Permalink
refactor: abstract useSubscription
Browse files Browse the repository at this point in the history
  • Loading branch information
crimx committed Aug 17, 2020
1 parent d9623f3 commit b9f8426
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 136 deletions.
77 changes: 3 additions & 74 deletions packages/observable-hooks/src/use-layout-subscription.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Observable, Subscription } from 'rxjs'
import { useForceUpdate, useIsomorphicLayoutEffect } from './helpers'
import { useRef } from 'react'
import { useIsomorphicLayoutEffect } from './helpers'
import { useSubscriptionInternal } from './use-subscription-internal'

// I know this is copy-paste from './useSubscription.ts'.
// Instead of leaving the performance penalty to users,
Expand Down Expand Up @@ -37,76 +37,5 @@ export function useLayoutSubscription<TInput>(
(() => void) | null | undefined
]
): React.MutableRefObject<Subscription | undefined> {
const argsRef = useRef(args)
argsRef.current = args

const forceUpdate = useForceUpdate()

const subscriptionRef = useRef<Subscription>()
const errorRef = useRef<Error | null>()

useIsomorphicLayoutEffect(() => {
errorRef.current = null

// keep in closure for checking staleness
const input$ = argsRef.current[0]

const subscription = input$.subscribe({
next: value => {
// layout effect runs synchronously
// this should never hit
// keeping for alignment to useEffect
/* istanbul ignore if */
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[1]) {
return argsRef.current[1](value)
}
},
error: error => {
// layout effect runs synchronously
// this should never hit
// keeping for alignment to useEffect
/* istanbul ignore if */
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[2]) {
errorRef.current = null
return argsRef.current[2](error)
}
errorRef.current = error
forceUpdate()
},
complete: () => {
// layout effect runs synchronously
// this should never hit
// keeping for alignment to useEffect
/* istanbul ignore if */
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[3]) {
return argsRef.current[3]()
}
}
})

subscriptionRef.current = subscription

return () => {
subscription.unsubscribe()
}
}, [args[0]])

if (errorRef.current) {
// Let error boundary catch the error
throw errorRef.current
}

return subscriptionRef
return useSubscriptionInternal(useIsomorphicLayoutEffect, args)
}
81 changes: 81 additions & 0 deletions packages/observable-hooks/src/use-subscription-internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Observable, Subscription } from 'rxjs'
import { useForceUpdate } from './helpers'
import { useEffect, useRef } from 'react'

/**
*
* @template TInput Input value within Observable.
*
* @param useCustomEffect useEffect or useLayoutEffect
* @param args collected arguments
*/
export function useSubscriptionInternal<TInput>(
useCustomEffect: typeof useEffect,
args: [
Observable<TInput>, // inputs$
((value: TInput) => void) | null | undefined, // next
((error: any) => void) | null | undefined, // error
(() => void) | null | undefined // complete
]
): React.MutableRefObject<Subscription | undefined> {
const argsRef = useRef(args)
argsRef.current = args

const forceUpdate = useForceUpdate()

const subscriptionRef = useRef<Subscription>()
const errorRef = useRef<Error | null>()

useCustomEffect(() => {
errorRef.current = null

// keep in closure for checking staleness
const input$ = argsRef.current[0]

const subscription = input$.subscribe({
next: value => {
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[1]) {
return argsRef.current[1](value)
}
},
error: error => {
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[2]) {
errorRef.current = null
return argsRef.current[2](error)
}
errorRef.current = error
forceUpdate()
},
complete: () => {
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[3]) {
return argsRef.current[3]()
}
}
})

subscriptionRef.current = subscription

return () => {
subscription.unsubscribe()
}
}, [args[0]])

if (errorRef.current) {
// Let error boundary catch the error
throw errorRef.current
}

return subscriptionRef
}
65 changes: 3 additions & 62 deletions packages/observable-hooks/src/use-subscription.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Observable, Subscription } from 'rxjs'
import { useForceUpdate } from './helpers'
import { useEffect, useRef } from 'react'
import { useEffect } from 'react'
import { useSubscriptionInternal } from './use-subscription-internal'

/**
* Accepts an Observable and optional `next`, `error`, `complete` functions.
Expand Down Expand Up @@ -52,64 +52,5 @@ export function useSubscription<TInput>(
(() => void) | null | undefined
]
): React.MutableRefObject<Subscription | undefined> {
const argsRef = useRef(args)
argsRef.current = args

const forceUpdate = useForceUpdate()

const subscriptionRef = useRef<Subscription>()
const errorRef = useRef<Error | null>()

useEffect(() => {
errorRef.current = null

// keep in closure for checking staleness
const input$ = argsRef.current[0]

const subscription = input$.subscribe({
next: value => {
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[1]) {
return argsRef.current[1](value)
}
},
error: error => {
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[2]) {
errorRef.current = null
return argsRef.current[2](error)
}
errorRef.current = error
forceUpdate()
},
complete: () => {
if (input$ !== argsRef.current[0]) {
// stale observable
return
}
if (argsRef.current[3]) {
return argsRef.current[3]()
}
}
})

subscriptionRef.current = subscription

return () => {
subscription.unsubscribe()
}
}, [args[0]])

if (errorRef.current) {
// Let error boundary catch the error
throw errorRef.current
}

return subscriptionRef
return useSubscriptionInternal(useEffect, args)
}

0 comments on commit b9f8426

Please sign in to comment.