|
1 | 1 | import type { Observable } from 'rxjs'; |
2 | | -import { useEffect, useState } from 'react'; |
| 2 | +import { useCallback } from 'react'; |
| 3 | +import { useSyncExternalStore } from 'use-sync-external-store/shim'; |
3 | 4 | import { RxUtils } from '@stream-io/video-client'; |
4 | 5 |
|
5 | 6 | /** |
6 | 7 | * Utility hook which provides the current value of the given observable. |
7 | 8 | * |
8 | 9 | * @param observable$ the observable to read data from. |
9 | | - * @param defaultValue a default value. Used when the observable data can't be read or emits an error. |
| 10 | + * @param defaultValue a default value. Used when the observable data can't be read or emits an error - must be stable. |
10 | 11 | */ |
11 | 12 | export const useObservableValue = <T>( |
12 | 13 | observable$: Observable<T>, |
13 | 14 | defaultValue?: T, |
14 | 15 | ) => { |
15 | | - const [value, setValue] = useState<T>(() => { |
| 16 | + const getSnapshot = useCallback(() => { |
16 | 17 | try { |
17 | 18 | return RxUtils.getCurrentValue(observable$); |
18 | | - } catch (err) { |
19 | | - if (typeof defaultValue === 'undefined') throw err; |
| 19 | + } catch (error) { |
| 20 | + if (typeof defaultValue === 'undefined') throw error; |
20 | 21 | return defaultValue; |
21 | 22 | } |
22 | | - }); |
23 | | - |
24 | | - useEffect(() => { |
25 | | - return RxUtils.createSubscription(observable$, setValue, (err) => { |
26 | | - console.log('An error occurred while reading an observable', err); |
27 | | - if (defaultValue) setValue(defaultValue); |
28 | | - }); |
29 | 23 | }, [defaultValue, observable$]); |
30 | 24 |
|
31 | | - return value; |
| 25 | + const subscribe = useCallback( |
| 26 | + (onStoreChange: (v: T) => void) => { |
| 27 | + const unsubscribe = RxUtils.createSubscription( |
| 28 | + observable$, |
| 29 | + onStoreChange, |
| 30 | + (error) => { |
| 31 | + console.log('An error occurred while reading an observable', error); |
| 32 | + |
| 33 | + if (defaultValue) onStoreChange(defaultValue); |
| 34 | + }, |
| 35 | + ); |
| 36 | + |
| 37 | + return unsubscribe; |
| 38 | + }, |
| 39 | + [defaultValue, observable$], |
| 40 | + ); |
| 41 | + |
| 42 | + return useSyncExternalStore(subscribe, getSnapshot); |
32 | 43 | }; |
0 commit comments