Skip to content

Commit 849e896

Browse files
authored
fix: revert usage of useSyncExternalStore (#2043)
Reverts #1953. In some environments, `useSyncExternalStore` causes misleading warnings that the result of `getSnapshot` should be cached. Although this isn't correct, I understand the confusion this warning creates. Until we find a way to get rid of it, I'm reverting to the old implementation of `useObservableValue`, based on `useState + useEffect` combo. Fixes: #2034 #2006 Ref: #2008
1 parent bbf41c8 commit 849e896

File tree

4 files changed

+16
-61
lines changed

4 files changed

+16
-61
lines changed

packages/client/src/store/CallState.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,29 +74,6 @@ type OrphanedTrack = {
7474
track: MediaStream;
7575
};
7676

77-
/**
78-
* Creates a stable participant filter function, ready to be used in combination
79-
* with the `useSyncExternalStore` hook.
80-
*
81-
* @param predicate the predicate to use.
82-
*/
83-
const createStableParticipantsFilter = (
84-
predicate: (p: StreamVideoParticipant) => boolean,
85-
) => {
86-
const empty: StreamVideoParticipant[] = [];
87-
return (participants: StreamVideoParticipant[]) => {
88-
// no need to filter if there are no participants
89-
if (!participants.length) return empty;
90-
91-
// return a stable empty array if there are no remote participants
92-
// instead of creating an empty one
93-
const filteredParticipants = participants.filter(predicate);
94-
if (!filteredParticipants.length) return empty;
95-
96-
return filteredParticipants;
97-
};
98-
};
99-
10077
/**
10178
* Holds the state of the current call.
10279
* @react You don't have to use this class directly, as we are exposing the state through Hooks.
@@ -376,12 +353,12 @@ export class CallState {
376353
);
377354

378355
this.remoteParticipants$ = this.participants$.pipe(
379-
map(createStableParticipantsFilter((p) => !p.isLocalParticipant)),
356+
map((participants) => participants.filter((p) => !p.isLocalParticipant)),
380357
shareReplay({ bufferSize: 1, refCount: true }),
381358
);
382359

383360
this.pinnedParticipants$ = this.participants$.pipe(
384-
map(createStableParticipantsFilter((p) => !!p.pin)),
361+
map((participants) => participants.filter((p) => !!p.pin)),
385362
shareReplay({ bufferSize: 1, refCount: true }),
386363
);
387364

packages/react-bindings/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
],
2323
"dependencies": {
2424
"i18next": "^25.6.0",
25-
"rxjs": "~7.8.2",
26-
"use-sync-external-store": "^1.6.0"
25+
"rxjs": "~7.8.2"
2726
},
2827
"peerDependencies": {
2928
"@stream-io/video-client": "workspace:^",
@@ -33,7 +32,6 @@
3332
"@rollup/plugin-typescript": "^12.1.4",
3433
"@stream-io/video-client": "workspace:^",
3534
"@types/react": "~19.1.17",
36-
"@types/use-sync-external-store": "^1",
3735
"react": "19.1.0",
3836
"rimraf": "^6.0.1",
3937
"rollup": "^4.52.4",
Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { Observable } from 'rxjs';
2-
import { useCallback } from 'react';
3-
import { useSyncExternalStore } from 'use-sync-external-store/shim';
2+
import { useEffect, useState } from 'react';
43
import { RxUtils } from '@stream-io/video-client';
54

65
/**
@@ -13,31 +12,21 @@ export const useObservableValue = <T>(
1312
observable$: Observable<T>,
1413
defaultValue?: T,
1514
) => {
16-
const getSnapshot = useCallback(() => {
15+
const [value, setValue] = useState<T>(() => {
1716
try {
1817
return RxUtils.getCurrentValue(observable$);
19-
} catch (error) {
20-
if (typeof defaultValue === 'undefined') throw error;
18+
} catch (err) {
19+
if (typeof defaultValue === 'undefined') throw err;
2120
return defaultValue;
2221
}
23-
}, [defaultValue, observable$]);
24-
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);
22+
});
3223

33-
if (defaultValue) onStoreChange(defaultValue);
34-
},
35-
);
36-
37-
return unsubscribe;
38-
},
39-
[defaultValue, observable$],
40-
);
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+
}, [defaultValue, observable$]);
4130

42-
return useSyncExternalStore(subscribe, getSnapshot);
31+
return value;
4332
};

yarn.lock

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7542,14 +7542,12 @@ __metadata:
75427542
"@rollup/plugin-typescript": "npm:^12.1.4"
75437543
"@stream-io/video-client": "workspace:^"
75447544
"@types/react": "npm:~19.1.17"
7545-
"@types/use-sync-external-store": "npm:^1"
75467545
i18next: "npm:^25.6.0"
75477546
react: "npm:19.1.0"
75487547
rimraf: "npm:^6.0.1"
75497548
rollup: "npm:^4.52.4"
75507549
rxjs: "npm:~7.8.2"
75517550
typescript: "npm:^5.9.3"
7552-
use-sync-external-store: "npm:^1.6.0"
75537551
peerDependencies:
75547552
"@stream-io/video-client": "workspace:^"
75557553
react: ^17 || ^18 || ^19
@@ -8422,13 +8420,6 @@ __metadata:
84228420
languageName: node
84238421
linkType: hard
84248422

8425-
"@types/use-sync-external-store@npm:^1":
8426-
version: 1.5.0
8427-
resolution: "@types/use-sync-external-store@npm:1.5.0"
8428-
checksum: 10/39e5be8dc2cca080b490f2f79fed4381ae7eebee3f981208e359856733eafb2479d229db07a552f6c99fe0b5c09b3e46a3e6a870e00a88b50f3e690e73d2649b
8429-
languageName: node
8430-
linkType: hard
8431-
84328423
"@types/whatwg-mimetype@npm:^3.0.2":
84338424
version: 3.0.2
84348425
resolution: "@types/whatwg-mimetype@npm:3.0.2"
@@ -24031,7 +24022,7 @@ __metadata:
2403124022
languageName: node
2403224023
linkType: hard
2403324024

24034-
"use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.5.0, use-sync-external-store@npm:^1.6.0":
24025+
"use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.5.0":
2403524026
version: 1.6.0
2403624027
resolution: "use-sync-external-store@npm:1.6.0"
2403724028
peerDependencies:

0 commit comments

Comments
 (0)