Skip to content

Commit d3b6013

Browse files
committed
useSyncExternalStore
1 parent 80b28b7 commit d3b6013

File tree

5 files changed

+64
-66
lines changed

5 files changed

+64
-66
lines changed

packages/core/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,11 @@
4848
"authors": [
4949
"Josep M Sobrepere (https://github.com/josepot)",
5050
"Victor Oliva (https://github.com/voliva)"
51-
]
51+
],
52+
"dependencies": {
53+
"use-sync-external-store": "^1.0.0-rc.0"
54+
},
55+
"devDependencies": {
56+
"@types/use-sync-external-store": "^0.0.3"
57+
}
5258
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Observable, Subscription } from "rxjs"
2+
import { SUSPENSE } from "../SUSPENSE"
23

34
export interface BehaviorObservable<T> extends Observable<T> {
4-
gV: (subscription?: Subscription) => T
5-
aH: any
5+
gV: (subscription?: Subscription) => Exclude<T, typeof SUSPENSE>
66
}

packages/core/src/internal/share-latest.ts

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,13 @@ const shareLatest = <T>(
7575
}
7676
}) as BehaviorObservable<T>
7777

78-
let error: any = EMPTY_VALUE
79-
let timeoutToken: any
80-
result.gV = (outterSubscription?: Subscription): T => {
81-
if ((currentValue as any) !== SUSPENSE && currentValue !== EMPTY_VALUE) {
82-
return currentValue
83-
}
84-
if (defaultValue !== EMPTY_VALUE) return defaultValue
78+
result.gV = (
79+
outterSubscription?: Subscription,
80+
): Exclude<T, typeof SUSPENSE> => {
81+
if ((currentValue as any) !== SUSPENSE && currentValue !== EMPTY_VALUE)
82+
return currentValue as any
8583

86-
if (error !== EMPTY_VALUE) {
87-
clearTimeout(timeoutToken)
88-
timeoutToken = setTimeout(() => {
89-
error = EMPTY_VALUE
90-
}, 50)
91-
throw error
92-
}
84+
if (defaultValue !== EMPTY_VALUE) return defaultValue as any
9385

9486
if (!subscription) {
9587
if (!outterSubscription) throw new Error("Missing Subscribe")
@@ -108,27 +100,23 @@ const shareLatest = <T>(
108100
if (promise) throw promise
109101

110102
throw (promise = new Promise<T>((res, rej) => {
111-
const setError = (e: any) => {
112-
error = e
113-
timeoutToken = setTimeout(() => {
114-
error = EMPTY_VALUE
115-
}, 50)
103+
const error = (e: any) => {
116104
rej(e)
117105
promise = null
118106
}
119-
const pSubs = subject!.subscribe(
120-
(v) => {
107+
const pSubs = subject!.subscribe({
108+
next: (v) => {
121109
if (v !== (SUSPENSE as any)) {
122110
pSubs.unsubscribe()
123111
res(v)
124112
promise = null
125113
}
126114
},
127-
setError,
128-
() => {
129-
setError(new Error("Empty observable"))
115+
error,
116+
complete: () => {
117+
error(new Error("Empty observable"))
130118
},
131-
)
119+
})
132120
subscription!.add(pSubs)
133121
}))
134122
}
Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,42 @@
1-
import { useEffect, useState, useRef } from "react"
2-
import { SUSPENSE } from "../SUSPENSE"
3-
import { BehaviorObservable } from "../internal/BehaviorObservable"
41
import { Subscription } from "rxjs"
2+
import { useSyncExternalStore } from "use-sync-external-store/shim"
3+
import { useRef, useState } from "react"
4+
import { BehaviorObservable } from "../internal/BehaviorObservable"
5+
import { SUSPENSE } from "../SUSPENSE"
6+
7+
type VoidCb = () => void
8+
9+
interface Ref<T> {
10+
args: [(cb: VoidCb) => VoidCb, () => Exclude<T, typeof SUSPENSE>]
11+
source$: BehaviorObservable<T>
12+
}
513

614
export const useObservable = <O>(
715
source$: BehaviorObservable<O>,
816
subscription?: Subscription,
917
): Exclude<O, typeof SUSPENSE> => {
10-
const [state, setState] = useState<[O, BehaviorObservable<O>]>(() => [
11-
source$.gV(subscription),
12-
source$,
13-
])
14-
const prevStateRef = useRef<O | (() => O)>(state[0])
18+
const [, setError] = useState()
19+
const callbackRef = useRef<Ref<O>>()
1520

16-
if (source$ !== state[1]) {
17-
setState([source$.gV(subscription), source$])
18-
}
19-
20-
useEffect(() => {
21-
const suspend = () => {
22-
setState(() => [source$.gV(), source$])
23-
}
21+
if (!callbackRef.current || callbackRef.current.source$ !== source$) {
22+
callbackRef.current = {
23+
source$,
24+
args: [
25+
(next: () => void) => {
26+
const subscription = source$.subscribe({
27+
next,
28+
error: (e) => {
29+
setError(() => {
30+
throw e
31+
})
32+
},
33+
})
2434

25-
const subscription = source$.subscribe(
26-
(value: O | typeof SUSPENSE) => {
27-
if (value === SUSPENSE) {
28-
suspend()
29-
} else {
30-
if (!Object.is(prevStateRef.current, value)) {
31-
setState([(prevStateRef.current = value), source$])
32-
}
33-
}
34-
},
35-
(error: any) => {
36-
setState(() => {
37-
throw error
38-
})
39-
},
40-
)
41-
42-
return () => {
43-
subscription.unsubscribe()
35+
return () => subscription.unsubscribe()
36+
},
37+
() => source$.gV(subscription),
38+
],
4439
}
45-
}, [source$])
46-
47-
return state[0] as Exclude<O, typeof SUSPENSE>
40+
}
41+
return useSyncExternalStore(...callbackRef.current!.args)
4842
}

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,11 @@
15881588
dependencies:
15891589
"@types/jest" "*"
15901590

1591+
"@types/use-sync-external-store@^0.0.3":
1592+
version "0.0.3"
1593+
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
1594+
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
1595+
15911596
"@types/yargs-parser@*":
15921597
version "20.2.0"
15931598
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9"
@@ -4501,6 +4506,11 @@ universalify@^0.1.2:
45014506
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
45024507
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
45034508

4509+
use-sync-external-store@^1.0.0-rc.0:
4510+
version "1.0.0-rc.0"
4511+
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.0.0-rc.0.tgz#0d8fb7cbc31ddfb3ee01225f6b0a700cf59c449b"
4512+
integrity sha512-0U9Xlc2QDFzSGMB0DvcJQL0+DIdxDPJC7mnZlYFbl7wrSrPMcs89X5TVkNB6Dzg618m8lZop+U+J6ow3vq9RAQ==
4513+
45044514
v8-to-istanbul@^8.1.0:
45054515
version "8.1.0"
45064516
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c"

0 commit comments

Comments
 (0)