Skip to content

Commit 92e1bef

Browse files
committed
feat(core): πŸŽ‰ Subscribe: Make source$ optional πŸŽ‰
1 parent f8afe0c commit 92e1bef

File tree

9 files changed

+365
-142
lines changed

9 files changed

+365
-142
lines changed

β€Žpackages/core/src/Subscribe.test.tsx

Lines changed: 218 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,110 +4,238 @@ import { defer, Observable, of } from "rxjs"
44
import { bind, Subscribe } from "./"
55

66
describe("Subscribe", () => {
7-
it("subscribes to the provided observable and remains subscribed until it's unmounted", () => {
8-
let nSubscriptions = 0
9-
const [useNumber, number$] = bind(
10-
new Observable<number>(() => {
11-
nSubscriptions++
12-
return () => {
13-
nSubscriptions--
14-
}
15-
}),
16-
)
7+
describe("Subscribe with source$", () => {
8+
it("subscribes to the provided observable and remains subscribed until it's unmounted", () => {
9+
let nSubscriptions = 0
10+
const [useNumber, number$] = bind(
11+
new Observable<number>(() => {
12+
nSubscriptions++
13+
return () => {
14+
nSubscriptions--
15+
}
16+
}),
17+
)
1718

18-
const Number: React.FC = () => <>{useNumber()}</>
19-
const TestSubscribe: React.FC = () => (
20-
<Subscribe source$={number$}>
21-
<Number />
22-
</Subscribe>
23-
)
19+
const Number: React.FC = () => <>{useNumber()}</>
20+
const TestSubscribe: React.FC = () => (
21+
<Subscribe source$={number$} fallback={null}>
22+
<Number />
23+
</Subscribe>
24+
)
2425

25-
expect(nSubscriptions).toBe(0)
26+
expect(nSubscriptions).toBe(0)
2627

27-
const { unmount } = render(<TestSubscribe />)
28+
const { unmount } = render(<TestSubscribe />)
2829

29-
expect(nSubscriptions).toBe(1)
30+
expect(nSubscriptions).toBe(1)
3031

31-
unmount()
32-
expect(nSubscriptions).toBe(0)
33-
})
32+
unmount()
33+
expect(nSubscriptions).toBe(0)
34+
})
3435

35-
it("doesn't render its content until it has subscribed to a new source", () => {
36-
let nSubscriptions = 0
37-
let errored = false
38-
const [useInstance, instance$] = bind((id: number) => {
39-
if (id === 0) {
40-
return of(0)
41-
}
42-
return defer(() => {
43-
nSubscriptions++
44-
return of(1)
36+
it("doesn't render its content until it has subscribed to a new source", () => {
37+
let nSubscriptions = 0
38+
let errored = false
39+
const [useInstance, instance$] = bind((id: number) => {
40+
if (id === 0) {
41+
return of(0)
42+
}
43+
return defer(() => {
44+
nSubscriptions++
45+
return of(1)
46+
})
4547
})
48+
49+
const Child = ({ id }: { id: number }) => {
50+
const value = useInstance(id)
51+
52+
if (id !== 0 && nSubscriptions === 0) {
53+
errored = true
54+
}
55+
56+
return <>{value}</>
57+
}
58+
const { rerender } = render(
59+
<Subscribe source$={instance$(0)}>
60+
<Child id={0} />
61+
</Subscribe>,
62+
)
63+
expect(nSubscriptions).toBe(0)
64+
expect(errored).toBe(false)
65+
66+
rerender(
67+
<Subscribe source$={instance$(1)}>
68+
<Child id={1} />
69+
</Subscribe>,
70+
)
71+
expect(nSubscriptions).toBe(1)
72+
expect(errored).toBe(false)
73+
74+
rerender(
75+
<Subscribe>
76+
<Child id={2} />
77+
</Subscribe>,
78+
)
79+
expect(nSubscriptions).toBe(2)
80+
expect(errored).toBe(false)
4681
})
4782

48-
const Child = ({ id }: { id: number }) => {
49-
const value = useInstance(id)
83+
it("prevents the issue of stale data when switching keys", () => {
84+
const [useInstance, instance$] = bind((id: number) => of(id))
85+
86+
const Child = ({
87+
id,
88+
initialValue,
89+
}: {
90+
id: number
91+
initialValue: number
92+
}) => {
93+
const [value] = useState(initialValue)
94+
95+
return (
96+
<>
97+
<div data-testid="id">{id}</div>
98+
<div data-testid="value">{value}</div>
99+
</>
100+
)
101+
}
102+
103+
const Parent = ({ id }: { id: number }) => {
104+
const value = useInstance(id)
50105

51-
if (id !== 0 && nSubscriptions === 0) {
52-
errored = true
106+
return <Child key={id} id={id} initialValue={value} />
53107
}
108+
const { rerender, getByTestId } = render(
109+
<Subscribe source$={instance$(0)}>
110+
<Parent id={0} />
111+
</Subscribe>,
112+
)
54113

55-
return <>{value}</>
56-
}
57-
const { rerender } = render(
58-
<Subscribe source$={instance$(0)}>
59-
<Child id={0} />
60-
</Subscribe>,
61-
)
62-
expect(nSubscriptions).toBe(0)
63-
expect(errored).toBe(false)
64-
65-
rerender(
66-
<Subscribe source$={instance$(1)}>
67-
<Child id={1} />
68-
</Subscribe>,
69-
)
70-
expect(nSubscriptions).toBe(1)
71-
expect(errored).toBe(false)
114+
rerender(
115+
<Subscribe source$={instance$(1)}>
116+
<Parent id={1} />
117+
</Subscribe>,
118+
)
119+
expect(getByTestId("id").textContent).toBe("1")
120+
expect(getByTestId("value").textContent).toBe("1")
121+
122+
const instanceTwoSubs = instance$(2).subscribe()
123+
rerender(
124+
<Subscribe source$={instance$(2)}>
125+
<Parent id={2} />
126+
</Subscribe>,
127+
)
128+
expect(getByTestId("id").textContent).toBe("2")
129+
expect(getByTestId("value").textContent).toBe("2")
130+
instanceTwoSubs.unsubscribe()
131+
})
72132
})
133+
describe("Subscribe without source$", () => {
134+
it("subscribes to the provided observable and remains subscribed until it's unmounted", () => {
135+
let nSubscriptions = 0
136+
const [useNumber] = bind(
137+
new Observable<number>(() => {
138+
nSubscriptions++
139+
return () => {
140+
nSubscriptions--
141+
}
142+
}),
143+
)
144+
145+
const Number: React.FC = () => <>{useNumber()}</>
146+
const TestSubscribe: React.FC = () => (
147+
<Subscribe fallback={null}>
148+
<Number />
149+
</Subscribe>
150+
)
151+
152+
expect(nSubscriptions).toBe(0)
153+
154+
const { unmount } = render(<TestSubscribe />)
155+
156+
expect(nSubscriptions).toBe(1)
73157

74-
it("prevents the issue of stale data when switching keys", () => {
75-
const [useInstance, instance$] = bind((id: number) => of(id))
76-
77-
const Child = ({
78-
id,
79-
initialValue,
80-
}: {
81-
id: number
82-
initialValue: number
83-
}) => {
84-
const [value] = useState(initialValue)
85-
86-
return (
87-
<>
88-
<div data-testid="id">{id}</div>
89-
<div data-testid="value">{value}</div>
90-
</>
158+
unmount()
159+
expect(nSubscriptions).toBe(0)
160+
})
161+
162+
it("doesn't render its content until it has subscribed to a new source", () => {
163+
let nSubscriptions = 0
164+
let errored = false
165+
const [useInstance] = bind((id: number) => {
166+
if (id === 0) {
167+
return of(0)
168+
}
169+
return defer(() => {
170+
nSubscriptions++
171+
return of(1)
172+
})
173+
})
174+
175+
const Child = ({ id }: { id: number }) => {
176+
const value = useInstance(id)
177+
178+
if (id !== 0 && nSubscriptions === 0) {
179+
errored = true
180+
}
181+
182+
return <>{value}</>
183+
}
184+
const { rerender } = render(
185+
<Subscribe>
186+
<Child id={0} />
187+
</Subscribe>,
91188
)
92-
}
93-
94-
const Parent = ({ id }: { id: number }) => {
95-
const value = useInstance(id)
96-
97-
return <Child key={id} id={id} initialValue={value} />
98-
}
99-
const { rerender, getByTestId } = render(
100-
<Subscribe source$={instance$(0)}>
101-
<Parent id={0} />
102-
</Subscribe>,
103-
)
104-
105-
rerender(
106-
<Subscribe source$={instance$(1)}>
107-
<Parent id={1} />
108-
</Subscribe>,
109-
)
110-
expect(getByTestId("id").textContent).toBe("1")
111-
expect(getByTestId("value").textContent).toBe("1")
189+
expect(nSubscriptions).toBe(0)
190+
expect(errored).toBe(false)
191+
192+
rerender(
193+
<Subscribe>
194+
<Child id={1} />
195+
</Subscribe>,
196+
)
197+
expect(nSubscriptions).toBe(1)
198+
expect(errored).toBe(false)
199+
})
200+
201+
it("prevents the issue of stale data when switching keys", () => {
202+
const [useInstance] = bind((id: number) => of(id))
203+
204+
const Child = ({
205+
id,
206+
initialValue,
207+
}: {
208+
id: number
209+
initialValue: number
210+
}) => {
211+
const [value] = useState(initialValue)
212+
213+
return (
214+
<>
215+
<div data-testid="id">{id}</div>
216+
<div data-testid="value">{value}</div>
217+
</>
218+
)
219+
}
220+
221+
const Parent = ({ id }: { id: number }) => {
222+
const value = useInstance(id)
223+
224+
return <Child key={id} id={id} initialValue={value} />
225+
}
226+
const { rerender, getByTestId } = render(
227+
<Subscribe>
228+
<Parent id={0} />
229+
</Subscribe>,
230+
)
231+
232+
rerender(
233+
<Subscribe>
234+
<Parent id={1} />
235+
</Subscribe>,
236+
)
237+
expect(getByTestId("id").textContent).toBe("1")
238+
expect(getByTestId("value").textContent).toBe("1")
239+
})
112240
})
113241
})

0 commit comments

Comments
Β (0)