Skip to content

Commit ccf81ed

Browse files
committed
perf(core): react-enhancer only returns a function
1 parent 8ea930d commit ccf81ed

File tree

6 files changed

+60
-68
lines changed

6 files changed

+60
-68
lines changed

packages/core/src/bind/connectFactoryObservable.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,11 @@ export default function connectFactoryObservable<A extends [], O>(
3030
(...args: A) => Exclude<O, typeof SUSPENSE>,
3131
(...args: A) => Observable<O>,
3232
] {
33-
const cache = new NestedMap<
34-
A,
35-
[BehaviorObservable<O>, BehaviorObservable<O>]
36-
>()
33+
const cache = new NestedMap<A, [BehaviorObservable<O>, () => O]>()
3734

3835
const getSharedObservables$ = (
3936
input: A,
40-
): [BehaviorObservable<O>, BehaviorObservable<O>] => {
37+
): [BehaviorObservable<O>, () => O] => {
4138
for (let i = input.length - 1; input[i] === undefined && i > -1; i--) {
4239
input.splice(-1)
4340
}
@@ -68,19 +65,23 @@ export default function connectFactoryObservable<A extends [], O>(
6865

6966
return source$.subscribe(subscriber)
7067
}) as BehaviorObservable<O>
71-
const reactObservable$ = reactEnhancer(publicShared$)
68+
publicShared$.getValue = sharedObservable$.getValue
69+
const reactGetValue = reactEnhancer(publicShared$)
7270

73-
const result: [BehaviorObservable<O>, BehaviorObservable<O>] = [
71+
const result: [BehaviorObservable<O>, () => O] = [
7472
publicShared$,
75-
reactObservable$,
73+
reactGetValue,
7674
]
7775

7876
cache.set(keys, result)
7977
return result
8078
}
8179

8280
return [
83-
(...input: A) => useObservable(getSharedObservables$(input)[1]),
81+
(...input: A) => {
82+
const [source$, getValue] = getSharedObservables$(input)
83+
return useObservable(source$, getValue)
84+
},
8485
(...input: A) => getSharedObservables$(input)[0],
8586
]
8687
}

packages/core/src/bind/connectObservable.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { useObservable } from "../internal/useObservable"
2020
*/
2121
export default function connectObservable<T>(observable: Observable<T>) {
2222
const sharedObservable$ = shareLatest<T>(observable, false)
23-
const reactObservable$ = reactEnhancer(sharedObservable$)
24-
const useStaticObservable = () => useObservable(reactObservable$)
23+
const getValue = reactEnhancer(sharedObservable$)
24+
const useStaticObservable = () => useObservable(sharedObservable$, getValue)
2525
return [useStaticObservable, sharedObservable$] as const
2626
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Observable } from "rxjs"
2+
import { SUSPENSE } from "../SUSPENSE"
23

34
export interface BehaviorObservable<T> extends Observable<T> {
4-
getValue: () => any
5+
getValue: () => T | typeof SUSPENSE
56
}
Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
import { Observable } from "rxjs"
21
import { SUSPENSE } from "../SUSPENSE"
32
import { BehaviorObservable } from "./BehaviorObservable"
43
import { EMPTY_VALUE } from "./empty-value"
54

6-
const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
7-
const result = new Observable<T>((subscriber) =>
8-
source$.subscribe(subscriber),
9-
) as BehaviorObservable<T>
10-
5+
const reactEnhancer = <T>(source$: BehaviorObservable<T>): (() => T) => {
116
let promise: Promise<T | void> | undefined
127
let error: any = EMPTY_VALUE
13-
const getValue = (): T => {
8+
9+
return (): T => {
10+
const currentValue = source$.getValue()
11+
if (currentValue !== SUSPENSE && currentValue !== EMPTY_VALUE) {
12+
return currentValue
13+
}
14+
1415
let timeoutToken
1516
if (error !== EMPTY_VALUE) {
1617
clearTimeout(timeoutToken)
@@ -20,44 +21,38 @@ const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
2021
throw error
2122
}
2223

23-
try {
24-
return (source$ as BehaviorObservable<T>).getValue()
25-
} catch (e) {
26-
if (promise) throw promise
27-
28-
let value: typeof EMPTY_VALUE | T = EMPTY_VALUE
29-
30-
promise = new Promise<T>((res) => {
31-
const subscription = result.subscribe(
32-
(v) => {
33-
if (v !== (SUSPENSE as any)) {
34-
value = v
35-
subscription && subscription.unsubscribe()
36-
res(v)
37-
}
38-
},
39-
(e) => {
40-
error = e
41-
timeoutToken = setTimeout(() => {
42-
error = EMPTY_VALUE
43-
}, 50)
44-
res()
45-
},
46-
)
47-
if (value !== EMPTY_VALUE) {
48-
subscription.unsubscribe()
49-
}
50-
}).finally(() => {
51-
promise = undefined
52-
})
53-
54-
if (value !== EMPTY_VALUE) return value
55-
56-
throw error !== EMPTY_VALUE ? error : promise
57-
}
24+
if (promise) throw promise
25+
26+
let value: typeof EMPTY_VALUE | T = EMPTY_VALUE
27+
28+
promise = new Promise<T>((res) => {
29+
const subscription = source$.subscribe(
30+
(v) => {
31+
if (v !== (SUSPENSE as any)) {
32+
value = v
33+
subscription && subscription.unsubscribe()
34+
res(v)
35+
}
36+
},
37+
(e) => {
38+
error = e
39+
timeoutToken = setTimeout(() => {
40+
error = EMPTY_VALUE
41+
}, 50)
42+
res()
43+
},
44+
)
45+
if (value !== EMPTY_VALUE) {
46+
subscription.unsubscribe()
47+
}
48+
}).finally(() => {
49+
promise = undefined
50+
})
51+
52+
if (value !== EMPTY_VALUE) return value
53+
54+
throw error !== EMPTY_VALUE ? error : promise
5855
}
59-
result.getValue = getValue
60-
return result
6156
}
6257

6358
export default reactEnhancer

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Observable, Subscription, Subject, noop } from "rxjs"
2-
import { SUSPENSE } from "../SUSPENSE"
32
import { BehaviorObservable } from "./BehaviorObservable"
43
import { EMPTY_VALUE } from "./empty-value"
54

@@ -58,12 +57,7 @@ const shareLatest = <T>(
5857
}
5958
}) as BehaviorObservable<T>
6059

61-
result.getValue = () => {
62-
if (currentValue === EMPTY_VALUE || currentValue === (SUSPENSE as any)) {
63-
throw currentValue
64-
}
65-
return currentValue
66-
}
60+
result.getValue = () => currentValue
6761

6862
return result
6963
}

packages/core/src/internal/useObservable.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import { useEffect, useState } from "react"
2-
import { BehaviorObservable } from "./BehaviorObservable"
32
import { SUSPENSE } from "../SUSPENSE"
43
import { EMPTY_VALUE } from "./empty-value"
4+
import { Observable } from "rxjs"
55

66
export const useObservable = <O>(
7-
source$: BehaviorObservable<O>,
7+
source$: Observable<O>,
8+
getValue: () => O,
89
): Exclude<O, typeof SUSPENSE> => {
9-
const [state, setState] = useState(source$.getValue)
10+
const [state, setState] = useState(getValue)
1011

1112
useEffect(() => {
1213
let prevVal: O | typeof SUSPENSE = EMPTY_VALUE
1314
let err: any = EMPTY_VALUE
1415

1516
const onNext = (value: O | typeof SUSPENSE) => {
1617
if (value === SUSPENSE) {
17-
setState(source$.getValue)
18+
setState(getValue)
1819
} else if (!Object.is(value, prevVal)) {
1920
setState(value)
2021
}
@@ -37,5 +38,5 @@ export const useObservable = <O>(
3738
return () => subscription.unsubscribe()
3839
}, [source$])
3940

40-
return state
41+
return state as Exclude<O, typeof SUSPENSE>
4142
}

0 commit comments

Comments
 (0)