v0.2.0-alpha.8

This commit is contained in:
Josep M Sobrepere 2020-06-06 20:14:37 +02:00
parent 1d5c8abf4d
commit e750dd13b8
8 changed files with 89 additions and 56 deletions

14
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "@josepot/react-rxjs",
"version": "0.2.0-alpha.7",
"version": "0.2.0-alpha.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1476,9 +1476,9 @@
}
},
"@testing-library/react-hooks": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-3.2.1.tgz",
"integrity": "sha512-1OB6Ksvlk6BCJA1xpj8/WWz0XVd1qRcgqdaFAq+xeC6l61Ucj0P6QpA5u+Db/x9gU4DCX8ziR5b66Mlfg0M2RA==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-3.3.0.tgz",
"integrity": "sha512-rE9geI1+HJ6jqXkzzJ6abREbeud6bLF8OmF+Vyc7gBoPwZAEVBYjbC1up5nNoVfYBhO5HUwdD4u9mTehAUeiyw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.5.4",
@ -9197,9 +9197,9 @@
"dev": true
},
"typescript": {
"version": "3.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz",
"integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==",
"version": "3.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
"integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
"dev": true
},
"unicode-canonical-property-names-ecmascript": {

View File

@ -1,5 +1,5 @@
{
"version": "0.2.0-alpha.7",
"version": "0.2.0-alpha.8",
"sideEffects": false,
"repository": {
"type": "git",
@ -37,7 +37,7 @@
"module": "dist/react-rxjs.esm.js",
"devDependencies": {
"@josepot/rxjs-utils": "^0.12.0",
"@testing-library/react-hooks": "^3.2.1",
"@testing-library/react-hooks": "^3.3.0",
"@types/jest": "^25.2.3",
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
@ -49,6 +49,6 @@
"rxjs": "^6.5.5",
"tsdx": "^0.13.2",
"tslib": "^2.0.0",
"typescript": "^3.9.3"
"typescript": "^3.9.5"
}
}

View File

@ -1,7 +1,7 @@
import { Observable, NEVER, concat } from "rxjs"
import distinctShareReplay from "./operators/distinct-share-replay"
import { FactoryObservableOptions, defaultFactoryOptions } from "./options"
import useSharedReplayableObservable from "./useSharedReplayableObservable"
import useObservable from "./useObservable"
export function connectFactoryObservable<
I,
@ -39,11 +39,7 @@ export function connectFactoryObservable<
return [
(...input: A) =>
useSharedReplayableObservable(
getSharedObservable$(...input),
initialValue,
options,
),
useObservable(getSharedObservable$(...input), initialValue, options),
getSharedObservable$,
]

View File

@ -1,7 +1,7 @@
import { Observable, NEVER, concat } from "rxjs"
import distinctShareReplay from "./operators/distinct-share-replay"
import { StaticObservableOptions, defaultStaticOptions } from "./options"
import useSharedReplayableObservable from "./useSharedReplayableObservable"
import useObservable from "./useObservable"
export function connectObservable<O, IO>(
observable: Observable<O>,
@ -18,7 +18,7 @@ export function connectObservable<O, IO>(
)
const useStaticObservable = () =>
useSharedReplayableObservable(sharedObservable$, initialValue, options)
useObservable(sharedObservable$, initialValue, options)
return [useStaticObservable, sharedObservable$] as const
}

View File

@ -2,4 +2,4 @@ export { connectObservable } from "./connectObservable"
export { connectFactoryObservable } from "./connectFactoryObservable"
export { connectInstanceObservable } from "./connectInstanceObservable"
export { default as distinctShareReplay } from "./operators/distinct-share-replay"
export { default as useSharedReplayableObservable } from "./useSharedReplayableObservable"
export { default as useObservable } from "./useObservable"

41
src/useObservable.ts Normal file
View File

@ -0,0 +1,41 @@
import { useState, useLayoutEffect } from "react"
import { Observable } from "rxjs"
import delayUnsubscription from "./operators/delay-unsubscription"
import { defaultFactoryOptions, ObservableOptions } from "./options"
const useObservable = <O, I>(
source$: Observable<O>,
initialValue: I,
options?: ObservableOptions,
) => {
const { suspenseTime, unsubscribeGraceTime } = {
...defaultFactoryOptions,
...options,
}
const [state, setState] = useState<I | O>(initialValue)
useLayoutEffect(() => {
let timeoutToken =
suspenseTime === Infinity
? undefined
: setTimeout(setState, suspenseTime, initialValue)
const stopInitialState = () => {
if (!timeoutToken) return
timeoutToken = clearTimeout(timeoutToken) as undefined
}
const subscription = delayUnsubscription(unsubscribeGraceTime)(
source$,
).subscribe(nextState => {
setState(nextState as any)
stopInitialState()
})
return () => subscription.unsubscribe()
}, [source$, suspenseTime, unsubscribeGraceTime])
return state
}
export default useObservable

View File

@ -1,37 +0,0 @@
import { useState, useLayoutEffect } from "react"
import { Observable, of, race, concat } from "rxjs"
import { delay } from "rxjs/operators"
import delayUnsubscription from "./operators/delay-unsubscription"
import { defaultFactoryOptions, ObservableOptions } from "./options"
const useSharedReplayableObservable = <O, I>(
sharedReplayableObservable$: Observable<O>,
initialValue: I,
options?: ObservableOptions,
) => {
const { suspenseTime, unsubscribeGraceTime } = {
...defaultFactoryOptions,
...options,
}
const [state, setState] = useState<I | O>(initialValue)
useLayoutEffect(() => {
const updates$ = sharedReplayableObservable$.pipe(
delayUnsubscription(unsubscribeGraceTime),
)
const subscription = (suspenseTime === Infinity
? updates$
: race(
concat(of(initialValue).pipe(delay(suspenseTime)), updates$),
updates$,
)
).subscribe(setState)
return () => subscription.unsubscribe()
}, [sharedReplayableObservable$, suspenseTime, unsubscribeGraceTime])
return state
}
export default useSharedReplayableObservable

View File

@ -0,0 +1,33 @@
import { defer, from, of } from "rxjs"
import { useObservable } from "../src"
import { renderHook, act } from "@testing-library/react-hooks"
import { concatMap, delay } from "rxjs/operators"
const wait = (ms: number) => new Promise(res => setTimeout(res, ms))
describe("useObservable", () => {
it("works", async () => {
let counter = 0
const source$ = defer(() => {
counter++
return from([1, 2, 3, 4]).pipe(concatMap(x => of(x).pipe(delay(10))))
})
const { result } = renderHook(() =>
useObservable(source$, 0, {
suspenseTime: 0,
unsubscribeGraceTime: 0,
}),
)
expect(result.current).toEqual(0)
expect(counter).toBe(1)
await act(async () => {
await wait(50)
})
expect(result.current).toEqual(4)
expect(counter).toBe(1)
})
})