Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/react-bindings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
],
"dependencies": {
"i18next": "^25.2.1",
"rxjs": "~7.8.1"
"rxjs": "~7.8.1",
"use-sync-external-store": "^1.6.0"
},
"peerDependencies": {
"@stream-io/video-client": "workspace:^",
Expand All @@ -32,6 +33,7 @@
"@rollup/plugin-typescript": "^12.1.2",
"@stream-io/video-client": "workspace:^",
"@types/react": "^19.2.0",
"@types/use-sync-external-store": "^1",
"react": "19.0.0",
"rimraf": "^6.0.1",
"rollup": "^4.40.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-bindings/src/hooks/callStateHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ function useLazyDeviceList(manager: DeviceManagerLike) {
setDevices$(manager.listDevices());
}

return devices;
return devices ?? EMPTY_DEVICES_ARRAY;
};

return { getDevices };
Expand Down
37 changes: 24 additions & 13 deletions packages/react-bindings/src/hooks/useObservableValue.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,43 @@
import type { Observable } from 'rxjs';
import { useEffect, useState } from 'react';
import { useCallback } from 'react';
import { useSyncExternalStore } from 'use-sync-external-store/shim';
import { RxUtils } from '@stream-io/video-client';

/**
* Utility hook which provides the current value of the given observable.
*
* @param observable$ the observable to read data from.
* @param defaultValue a default value. Used when the observable data can't be read or emits an error.
* @param defaultValue a default value. Used when the observable data can't be read or emits an error - must be stable.
*/
export const useObservableValue = <T>(
observable$: Observable<T>,
defaultValue?: T,
) => {
const [value, setValue] = useState<T>(() => {
const getSnapshot = useCallback(() => {
try {
return RxUtils.getCurrentValue(observable$);
} catch (err) {
if (typeof defaultValue === 'undefined') throw err;
} catch (error) {
if (typeof defaultValue === 'undefined') throw error;
return defaultValue;
}
});

useEffect(() => {
return RxUtils.createSubscription(observable$, setValue, (err) => {
console.log('An error occurred while reading an observable', err);
if (defaultValue) setValue(defaultValue);
});
}, [defaultValue, observable$]);

return value;
const subscribe = useCallback(
(onStoreChange: (v: T) => void) => {
const unsubscribe = RxUtils.createSubscription(
observable$,
onStoreChange,
(error) => {
console.log('An error occurred while reading an observable', error);

if (defaultValue) onStoreChange(defaultValue);
},
);

return unsubscribe;
},
[defaultValue, observable$],
);

return useSyncExternalStore(subscribe, getSnapshot);
};
18 changes: 18 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8763,12 +8763,14 @@ __metadata:
"@rollup/plugin-typescript": "npm:^12.1.2"
"@stream-io/video-client": "workspace:^"
"@types/react": "npm:^19.2.0"
"@types/use-sync-external-store": "npm:^1"
i18next: "npm:^25.2.1"
react: "npm:19.0.0"
rimraf: "npm:^6.0.1"
rollup: "npm:^4.40.2"
rxjs: "npm:~7.8.1"
typescript: "npm:^5.8.3"
use-sync-external-store: "npm:^1.6.0"
peerDependencies:
"@stream-io/video-client": "workspace:^"
react: ^17 || ^18 || ^19
Expand Down Expand Up @@ -9658,6 +9660,13 @@ __metadata:
languageName: node
linkType: hard

"@types/use-sync-external-store@npm:^1":
version: 1.5.0
resolution: "@types/use-sync-external-store@npm:1.5.0"
checksum: 10/39e5be8dc2cca080b490f2f79fed4381ae7eebee3f981208e359856733eafb2479d229db07a552f6c99fe0b5c09b3e46a3e6a870e00a88b50f3e690e73d2649b
languageName: node
linkType: hard

"@types/ws@npm:^8.5.14":
version: 8.18.1
resolution: "@types/ws@npm:8.18.1"
Expand Down Expand Up @@ -27008,6 +27017,15 @@ __metadata:
languageName: node
linkType: hard

"use-sync-external-store@npm:^1.6.0":
version: 1.6.0
resolution: "use-sync-external-store@npm:1.6.0"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
checksum: 10/b40ad2847ba220695bff2d4ba4f4d60391c0fb4fb012faa7a4c18eb38b69181936f5edc55a522c4d20a788d1a879b73c3810952c9d0fd128d01cb3f22042c09e
languageName: node
linkType: hard

"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1":
version: 1.0.2
resolution: "util-deprecate@npm:1.0.2"
Expand Down
Loading