Skip to content

Commit d4ac471

Browse files
committed
chore(core): remove graceTime
1 parent 35527ed commit d4ac471

File tree

4 files changed

+80
-89
lines changed

4 files changed

+80
-89
lines changed

packages/core/src/bind/connectFactoryObservable.test.tsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
Subject,
1010
} from "rxjs"
1111
import { renderHook, act as actHook } from "@testing-library/react-hooks"
12-
import { switchMap, delay, take } from "rxjs/operators"
12+
import { switchMap, delay, take, catchError } from "rxjs/operators"
1313
import { FC, Suspense, useState } from "react"
1414
import React from "react"
1515
import {
@@ -55,7 +55,8 @@ describe("connectFactoryObservable", () => {
5555

5656
it("suspends the component when the observable hasn't emitted yet.", async () => {
5757
const source$ = of(1).pipe(delay(100))
58-
const [useDelayedNumber] = bind(() => source$)
58+
const [useDelayedNumber, getDelayedNumber$] = bind(() => source$)
59+
const subs = getDelayedNumber$().subscribe()
5960
const Result: React.FC = () => <div>Result {useDelayedNumber()}</div>
6061
const TestSuspense: React.FC = () => {
6162
return (
@@ -74,6 +75,7 @@ describe("connectFactoryObservable", () => {
7475

7576
expect(screen.queryByText("Result 1")).not.toBeNull()
7677
expect(screen.queryByText("Waiting")).toBeNull()
78+
subs.unsubscribe()
7779
})
7880

7981
it("shares the multicasted subscription with all of the components that use the same parameters", async () => {
@@ -92,19 +94,21 @@ describe("connectFactoryObservable", () => {
9294
expect(subscriberCount).toBe(0)
9395

9496
const first = { val: 1 }
97+
latestNumber$(1, first).subscribe()
9598
renderHook(() => useLatestNumber(1, first))
9699
expect(subscriberCount).toBe(1)
97100

98101
renderHook(() => useLatestNumber(1, first))
99102
expect(subscriberCount).toBe(1)
100103

101-
latestNumber$(1, first).subscribe()
102104
expect(subscriberCount).toBe(1)
103105

104106
const second = { val: 2 }
107+
latestNumber$(1, second).subscribe()
105108
renderHook(() => useLatestNumber(1, second))
106109
expect(subscriberCount).toBe(2)
107110

111+
latestNumber$(2, second).subscribe()
108112
renderHook(() => useLatestNumber(2, second))
109113
expect(subscriberCount).toBe(3)
110114
})
@@ -135,7 +139,9 @@ describe("connectFactoryObservable", () => {
135139
})
136140

137141
it("suspends the component when the factory-observable hasn't emitted yet.", async () => {
138-
const [useDelayedNumber] = bind((x: number) => of(x).pipe(delay(50)))
142+
const [useDelayedNumber, getDelayedNumber$] = bind((x: number) =>
143+
of(x).pipe(delay(50)),
144+
)
139145
const Result: React.FC<{ input: number }> = (p) => (
140146
<div>Result {useDelayedNumber(p.input)}</div>
141147
)
@@ -151,6 +157,7 @@ describe("connectFactoryObservable", () => {
151157
)
152158
}
153159

160+
getDelayedNumber$(0).subscribe()
154161
render(<TestSuspense />)
155162
expect(screen.queryByText("Result")).toBeNull()
156163
expect(screen.queryByText("Waiting")).not.toBeNull()
@@ -161,6 +168,7 @@ describe("connectFactoryObservable", () => {
161168
expect(screen.queryByText("Waiting")).toBeNull()
162169

163170
componentAct(() => {
171+
getDelayedNumber$(1).subscribe()
164172
fireEvent.click(screen.getByText(/increase/i))
165173
})
166174
expect(screen.queryByText("Result")).toBeNull()
@@ -172,6 +180,7 @@ describe("connectFactoryObservable", () => {
172180
expect(screen.queryByText("Waiting")).toBeNull()
173181

174182
componentAct(() => {
183+
getDelayedNumber$(2).subscribe()
175184
fireEvent.click(screen.getByText(/increase/i))
176185
})
177186
expect(screen.queryByText("Result")).toBeNull()
@@ -190,9 +199,10 @@ describe("connectFactoryObservable", () => {
190199
return from([1, 2, 3, 4, 5])
191200
})
192201

193-
const [useLatestNumber] = bind((id: number) =>
202+
const [useLatestNumber, getLatestNumber$] = bind((id: number) =>
194203
concat(observable$, of(id)),
195204
)
205+
let subs = getLatestNumber$(6).subscribe()
196206
const { unmount } = renderHook(() => useLatestNumber(6))
197207
const { unmount: unmount2 } = renderHook(() => useLatestNumber(6))
198208
const { unmount: unmount3 } = renderHook(() => useLatestNumber(6))
@@ -201,13 +211,13 @@ describe("connectFactoryObservable", () => {
201211
unmount2()
202212
unmount3()
203213

204-
await wait(230)
205214
const { unmount: unmount4 } = renderHook(() => useLatestNumber(6))
206215
expect(nInitCount).toBe(1)
207216

208217
unmount4()
209-
await wait(270)
218+
subs.unsubscribe()
210219

220+
getLatestNumber$(6).subscribe()
211221
renderHook(() => useLatestNumber(6))
212222
expect(nInitCount).toBe(2)
213223
})
@@ -307,7 +317,13 @@ describe("connectFactoryObservable", () => {
307317
observer.error("controlled error")
308318
})
309319

310-
const [useOkKo] = bind((ok: boolean) => (ok ? normal$ : errored$))
320+
const [useOkKo, getObs$] = bind((ok: boolean) =>
321+
ok ? normal$ : errored$,
322+
)
323+
getObs$(true).subscribe()
324+
getObs$(false)
325+
.pipe(catchError(() => []))
326+
.subscribe()
311327

312328
const ErrorComponent = () => {
313329
const [ok, setOk] = useState(true)
@@ -407,6 +423,7 @@ describe("connectFactoryObservable", () => {
407423
expect(sub1.closed).toBe(false)
408424
sub1.unsubscribe()
409425

426+
let sub = getShared(0).subscribe()
410427
const { result, unmount } = renderHook(() => useLatestNumber(0))
411428
expect(result.current).toBe(5)
412429
expect(nUpdates).toBe(4)
@@ -432,7 +449,7 @@ describe("connectFactoryObservable", () => {
432449
sub3.unsubscribe()
433450

434451
unmount()
435-
await wait(260)
452+
sub.unsubscribe()
436453

437454
let latestValue4: number = 0
438455
const sub4 = getShared(0).subscribe((x) => {

packages/core/src/bind/connectObservable.test.tsx

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@ import {
1414
Subject,
1515
throwError,
1616
Observable,
17-
concat,
1817
} from "rxjs"
19-
import { delay, scan, startWith, map, switchMap } from "rxjs/operators"
18+
import {
19+
delay,
20+
scan,
21+
startWith,
22+
map,
23+
switchMap,
24+
catchError,
25+
} from "rxjs/operators"
2026
import { bind, SUSPENSE } from "../"
2127
import { TestErrorBoundary } from "../test-helpers/TestErrorBoundary"
2228

@@ -51,7 +57,33 @@ describe("connectObservable", () => {
5157

5258
it("suspends the component when the observable hasn't emitted yet.", async () => {
5359
const source$ = of(1).pipe(delay(100))
54-
const [useDelayedNumber] = bind(source$)
60+
const [useDelayedNumber, delayedNumber$] = bind(source$)
61+
const sub = delayedNumber$.subscribe()
62+
const Result: React.FC = () => <div>Result {useDelayedNumber()}</div>
63+
const TestSuspense: React.FC = () => {
64+
return (
65+
<Suspense fallback={<span>Waiting</span>}>
66+
<Result />
67+
</Suspense>
68+
)
69+
}
70+
71+
render(<TestSuspense />)
72+
73+
expect(screen.queryByText("Result")).toBeNull()
74+
expect(screen.queryByText("Waiting")).not.toBeNull()
75+
76+
await wait(110)
77+
78+
expect(screen.queryByText("Result 1")).not.toBeNull()
79+
expect(screen.queryByText("Waiting")).toBeNull()
80+
sub.unsubscribe()
81+
})
82+
83+
it("suspends the component when the observable starts emitting suspense", async () => {
84+
const source$ = of(1).pipe(delay(100), startWith(SUSPENSE))
85+
const [useDelayedNumber, delayedNumber$] = bind(source$)
86+
const sub = delayedNumber$.subscribe()
5587
const Result: React.FC = () => <div>Result {useDelayedNumber()}</div>
5688
const TestSuspense: React.FC = () => {
5789
return (
@@ -70,6 +102,7 @@ describe("connectObservable", () => {
70102

71103
expect(screen.queryByText("Result 1")).not.toBeNull()
72104
expect(screen.queryByText("Waiting")).toBeNull()
105+
sub.unsubscribe()
73106
})
74107

75108
it("updates with the last emitted value", async () => {
@@ -157,14 +190,15 @@ describe("connectObservable", () => {
157190
expect(updates).toHaveBeenCalledTimes(2)
158191
})
159192

160-
it("shares the source subscription until the refCount has stayed at zero for the grace-period", async () => {
193+
it("shares the source subscription until there are no more subscribers", async () => {
161194
let nInitCount = 0
162195
const observable$ = defer(() => {
163196
nInitCount += 1
164197
return from([1, 2, 3, 4, 5])
165198
})
166199

167-
const [useLatestNumber] = bind(observable$)
200+
const [useLatestNumber, latestNumber$] = bind(observable$)
201+
let subs = latestNumber$.subscribe()
168202
const { unmount } = renderHook(() => useLatestNumber())
169203
const { unmount: unmount2 } = renderHook(() => useLatestNumber())
170204
const { unmount: unmount3 } = renderHook(() => useLatestNumber())
@@ -173,12 +207,12 @@ describe("connectObservable", () => {
173207
unmount2()
174208
unmount3()
175209

176-
await wait(230)
177210
const { unmount: unmount4 } = renderHook(() => useLatestNumber())
178211
expect(nInitCount).toBe(1)
179212
unmount4()
180213

181-
await wait(270)
214+
subs.unsubscribe()
215+
subs = latestNumber$.subscribe()
182216
renderHook(() => useLatestNumber())
183217
expect(nInitCount).toBe(2)
184218
})
@@ -352,7 +386,7 @@ describe("connectObservable", () => {
352386

353387
it("allows to retry the errored observable after a grace period of time", async () => {
354388
let errStream = new Subject<string>()
355-
const [useError] = bind(
389+
const [useError, error$] = bind(
356390
defer(() => {
357391
return (errStream = new Subject<string>())
358392
}),
@@ -364,6 +398,7 @@ describe("connectObservable", () => {
364398
}
365399

366400
const errorCallback = jest.fn()
401+
error$.pipe(catchError(() => [])).subscribe()
367402
const { unmount } = render(
368403
<TestErrorBoundary onError={errorCallback}>
369404
<Suspense fallback={<div>Loading...</div>}>
@@ -390,8 +425,9 @@ describe("connectObservable", () => {
390425

391426
errorCallback.mockReset()
392427
await componentAct(async () => {
393-
await wait(250)
428+
await wait(200)
394429
})
430+
error$.subscribe()
395431

396432
render(
397433
<TestErrorBoundary onError={errorCallback}>
@@ -448,42 +484,4 @@ describe("connectObservable", () => {
448484

449485
expect(errorCallback).not.toHaveBeenCalled()
450486
})
451-
452-
it("handles combined Suspended components that resolve at different times", async () => {
453-
let nSideEffects = 0
454-
const fast$ = defer(() => {
455-
nSideEffects++
456-
return of("fast")
457-
}).pipe(delay(5))
458-
const slow$ = defer(() => {
459-
nSideEffects++
460-
return of("slow")
461-
}).pipe(delay(2500))
462-
463-
const [useFast] = bind(concat(of(SUSPENSE), fast$))
464-
const [useSlow] = bind(concat(of(SUSPENSE), slow$))
465-
466-
const Fast: React.FC = () => <>{useFast()}</>
467-
const Slow: React.FC = () => <>{useSlow()}</>
468-
469-
expect(nSideEffects).toBe(0)
470-
471-
render(
472-
<Suspense fallback={<div>Loading...</div>}>
473-
<Slow />
474-
<Fast />
475-
</Suspense>,
476-
)
477-
478-
expect(screen.queryByText("Loading...")).not.toBeNull()
479-
480-
expect(nSideEffects).toBe(2)
481-
482-
await componentAct(async () => {
483-
await wait(2600)
484-
})
485-
486-
expect(screen.queryByText("Loading...")).toBeNull()
487-
expect(nSideEffects).toBe(2)
488-
})
489487
})

packages/core/src/internal/react-enhancer.ts

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,21 @@
1-
import { Observable, noop } from "rxjs"
1+
import { Observable } from "rxjs"
22
import { SUSPENSE } from "../SUSPENSE"
33
import { BehaviorObservable, Action } from "./BehaviorObservable"
44
import { EMPTY_VALUE } from "./empty-value"
55

66
const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
7-
let refCount = 0
8-
let finalizeLastUnsubscription = noop
9-
107
const result = new Observable<T>((subscriber) => {
11-
refCount++
12-
let isActive = true
138
let latestValue = EMPTY_VALUE
14-
const subscription = source$.subscribe(
9+
return source$.subscribe(
1510
(value) => {
16-
if (isActive && !Object.is(latestValue, value)) {
11+
if (!Object.is(latestValue, value)) {
1712
subscriber.next((latestValue = value))
1813
}
1914
},
2015
(e) => {
2116
subscriber.error(e)
2217
},
2318
)
24-
finalizeLastUnsubscription()
25-
return () => {
26-
refCount--
27-
if (refCount > 0 || subscription.closed) {
28-
return subscription.unsubscribe()
29-
}
30-
31-
isActive = false
32-
const timeoutToken = setTimeout(() => {
33-
finalizeLastUnsubscription()
34-
}, 250)
35-
36-
finalizeLastUnsubscription = () => {
37-
clearTimeout(timeoutToken)
38-
subscription.unsubscribe()
39-
finalizeLastUnsubscription = noop
40-
}
41-
}
4219
}) as BehaviorObservable<T>
4320

4421
let promise: undefined | { type: Action.Suspense; payload: Promise<T | void> }
@@ -86,7 +63,7 @@ const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
8663
res()
8764
},
8865
)
89-
if (value !== EMPTY_VALUE || error !== EMPTY_VALUE) {
66+
if (value !== EMPTY_VALUE) {
9067
subscription.unsubscribe()
9168
}
9269
}).finally(() => {
@@ -98,11 +75,7 @@ const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
9875
return value
9976
}
10077

101-
if (error !== EMPTY_VALUE) {
102-
return error
103-
}
104-
105-
return promise
78+
return error !== EMPTY_VALUE ? error : promise
10679
}
10780
}
10881
result.getValue = getValue

packages/dom/src/batchUpdates.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { Component, ErrorInfo, useEffect } from "react"
22
import { Observable, throwError, concat, Subject } from "rxjs"
3-
import { mergeMapTo, take, filter } from "rxjs/operators"
3+
import { mergeMapTo, take, filter, catchError } from "rxjs/operators"
44
import { bind, Subscribe } from "@react-rxjs/core"
55
import { batchUpdates } from "./"
66
import { act, render, screen } from "@testing-library/react"
@@ -149,6 +149,9 @@ describe("batchUpdates", () => {
149149
test("batchUpdates doesn't get in the way of Error Boundaries", async () => {
150150
const mockFn = jest.fn()
151151
const errorCallback = jest.fn()
152+
latestNumber$(true, true)
153+
.pipe(catchError(() => []))
154+
.subscribe()
152155
render(
153156
<TestErrorBoundary onError={errorCallback}>
154157
<Father batched error onRender={mockFn} />

0 commit comments

Comments
 (0)