-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: let use-subscription support closure accessing
deprecated use-observable-props-callback in favor or the new use-subscription BREAKING CHANGE: useSubscription supports only one way to pass subscribe arguments for simplicity. |useSubscription used to ignore changes of the subscribe functions, now it will always call the latest one.
- Loading branch information
Showing
4 changed files
with
169 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,8 @@ | ||
import { Observable, Subscription } from 'rxjs' | ||
import { withLatestFrom } from 'rxjs/operators' | ||
import { useSubscription } from './use-subscription' | ||
import { useObservable } from './use-observable' | ||
|
||
/** | ||
* Whenever the Observable emits a value, callback | ||
* is called with that value. | ||
* | ||
* Note that changes of callback will not trigger | ||
* an emission. If you need that just create another | ||
* Observable with `useObservable`. | ||
* | ||
* Examples: | ||
* | ||
* ```typescript | ||
* const events$ = useObservable(() => interval(1000)) | ||
* | ||
* useObservablePropsCallback(events$, props.onChange) | ||
* ``` | ||
* | ||
* So why not use [[useSubscription]]? | ||
* | ||
* ```typescript | ||
* useSubscription(events$, props.onChange) | ||
* ``` | ||
* | ||
* [[useSubscription]] works the same if `props.onChange` never changes. | ||
* `useObservablePropsCallback` ensures the latest `props.onChange` is called. | ||
* @deprecated use [[useSubscription]] instead. | ||
*/ | ||
export function useObservablePropsCallback<Event>( | ||
events$: Observable<Event>, | ||
callback: (e: Event) => any | ||
): Subscription { | ||
const enhanced$ = useObservable( | ||
callbacks$ => events$.pipe(withLatestFrom(callbacks$)), | ||
[callback] as [typeof callback] | ||
) | ||
return useSubscription(enhanced$, subscribe) | ||
} | ||
|
||
/** @ignore */ | ||
function subscribe<E, T extends Function>([e, [callback]]: [E, [T]]) { | ||
callback(e) | ||
} | ||
export const useObservablePropsCallback = useSubscription |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,103 @@ | ||
import { PartialObserver, Observable, Subscription } from 'rxjs' | ||
import { useRefFn } from './helpers' | ||
import { useEffect } from 'react' | ||
import { Observable, Subscription } from 'rxjs' | ||
import { useRefFn, emptyTuple } from './helpers' | ||
import { useEffect, useRef } from 'react' | ||
|
||
/** | ||
* Accepts an Observable and RxJS subscribe parameters. | ||
* Deprecated subscribe parameter types are not included | ||
* but you can use it anyway if not writing TypeScript. | ||
* Accepts an Observable and optional `next`, `error`, `complete` functions. | ||
* These functions must be in correct order. | ||
* Use `undefined` or `null` for placeholder. | ||
* | ||
* Subscription will unsubscribe when unmount, you can also | ||
* unsubscribe manually. | ||
* | ||
* Note that `useSubscription` will only subscribe once. | ||
* Subsequent changes of the callback functions will be ignored. | ||
* If you need that, take a look at [[useObservablePropsCallback]] | ||
* or create an stream of callbacks yourself. | ||
* Note that changes of callbacks will not trigger | ||
* an emission. If you need that just create another | ||
* Observable of the callback with [[useObservable]]. | ||
* | ||
* You can also access closure in the callback like in `useEffect`. | ||
* `useSubscription` will ensure the latest callback is called. | ||
* | ||
* Examples: | ||
* | ||
* ```typescript | ||
* const subscription = useSubscription(events$, e => console.log(e.type)) | ||
* ``` | ||
* | ||
* Or: | ||
* On complete | ||
* | ||
* ```typescript | ||
* const subscription = useSubscription(events$, null, null, () => console.log('complete')) | ||
* ``` | ||
* | ||
* Access closure: | ||
* | ||
* ```typescript | ||
* const subscription = useSubscription(events$, { | ||
* next: console.log, | ||
* error: console.error, | ||
* complete: () => console.log('complete') | ||
* const [debug, setDebug] = useState(false) | ||
* const subscription = useSubscription(events$, null, error => { | ||
* if (debug) { | ||
* console.log(error) | ||
* } | ||
* }) | ||
* ``` | ||
*/ | ||
export function useSubscription<T>(stream$: Observable<T>): Subscription | ||
export function useSubscription<T>( | ||
stream$: Observable<T>, | ||
observer?: PartialObserver<T> | ||
next: (value: T) => void | null | undefined | ||
): Subscription | ||
export function useSubscription<T>( | ||
stream$: Observable<T>, | ||
next?: (value: T) => void, | ||
error?: (error: any) => void, | ||
complete?: () => void | ||
next: (value: T) => void | null | undefined, | ||
error: (error: any) => void | null | undefined | ||
): Subscription | ||
export function useSubscription<T>( | ||
stream$: Observable<T>, | ||
...args: any[] | ||
next: (value: T) => void | null | undefined, | ||
error: (error: any) => void | null | undefined, | ||
complete: () => void | null | undefined | ||
): Subscription | ||
export function useSubscription<T>( | ||
stream$: Observable<T>, | ||
...args: | ||
| [] | ||
| [(value: T) => void | null | undefined] | ||
| [ | ||
(value: T) => void | null | undefined, | ||
(error: any) => void | null | undefined | ||
] | ||
| [ | ||
(value: T) => void | null | undefined, | ||
(error: any) => void | null | undefined, | ||
() => void | null | undefined | ||
] | ||
): Subscription { | ||
const subscriptionRef = useRefFn(() => stream$.subscribe(...args)) | ||
const argsRef = useRef< | ||
Readonly< | ||
| [] | ||
| [(value: T) => void | null | undefined] | ||
| [ | ||
(value: T) => void | null | undefined, | ||
(error: any) => void | null | undefined | ||
] | ||
| [ | ||
(value: T) => void | null | undefined, | ||
(error: any) => void | null | undefined, | ||
() => void | null | undefined | ||
] | ||
> | ||
>(emptyTuple) | ||
argsRef.current = args | ||
|
||
const subscriptionRef = useRefFn(() => | ||
stream$.subscribe({ | ||
next: value => argsRef.current[0] && argsRef.current[0](value), | ||
error: error => argsRef.current[1] && argsRef.current[1](error), | ||
complete: () => argsRef.current[2] && argsRef.current[2]() | ||
}) | ||
) | ||
|
||
// unsubscribe when unmount | ||
useEffect(() => () => subscriptionRef.current.unsubscribe(), []) | ||
|
||
return subscriptionRef.current | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters