diff --git a/package.json b/package.json index b25c746b28..cc49638f63 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "eslint": "^9.26.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-hooks": "^6.1.0", "globals": "^16.1.0", "husky": "^9.1.7", "lint-staged": "^15.5.2", diff --git a/packages/react-bindings/package.json b/packages/react-bindings/package.json index b9b6508fc4..fbfbd1b350 100644 --- a/packages/react-bindings/package.json +++ b/packages/react-bindings/package.json @@ -31,7 +31,7 @@ "devDependencies": { "@rollup/plugin-typescript": "^12.1.2", "@stream-io/video-client": "workspace:^", - "@types/react": "^19.1.3", + "@types/react": "^19.2.0", "react": "19.0.0", "rimraf": "^6.0.1", "rollup": "^4.40.2", diff --git a/packages/react-bindings/src/hooks/index.ts b/packages/react-bindings/src/hooks/index.ts index a8e197a77e..10bf1ec5c8 100644 --- a/packages/react-bindings/src/hooks/index.ts +++ b/packages/react-bindings/src/hooks/index.ts @@ -1,5 +1,5 @@ import * as CallStateHooks from './callStateHooks'; - +export * from './useEffectEvent'; export * from './useObservableValue'; export * from './store'; diff --git a/packages/react-bindings/src/hooks/useEffectEvent.ts b/packages/react-bindings/src/hooks/useEffectEvent.ts new file mode 100644 index 0000000000..a1b903432e --- /dev/null +++ b/packages/react-bindings/src/hooks/useEffectEvent.ts @@ -0,0 +1,23 @@ +import { + useCallback, + useLayoutEffect, + useRef, + useEffectEvent as BuiltInHook, +} from 'react'; + +function useEffectEventShim any>( + cb: T, +): (...funcArgs: Parameters) => ReturnType { + const cbRef = useRef(cb); + + useLayoutEffect(() => { + cbRef.current = cb; + }, [cb]); + + return useCallback((...args: Parameters) => { + const callback = cbRef.current; + return callback(...args); + }, []); +} + +export const useEffectEvent = BuiltInHook ?? useEffectEventShim; diff --git a/packages/react-native-sdk/src/hooks/usePermissionNotification.tsx b/packages/react-native-sdk/src/hooks/usePermissionNotification.tsx index a9f5127e17..7d12f25a80 100644 --- a/packages/react-native-sdk/src/hooks/usePermissionNotification.tsx +++ b/packages/react-native-sdk/src/hooks/usePermissionNotification.tsx @@ -1,8 +1,9 @@ import { CallingState, OwnCapability } from '@stream-io/video-client'; import { useCallStateHooks } from '@stream-io/video-react-bindings'; -import { useCallback, useEffect } from 'react'; +import { useEffect } from 'react'; import { Alert } from 'react-native'; import { usePrevious } from '../utils/hooks/usePrevious'; +import { useEffectEvent } from '@stream-io/video-react-bindings'; export type PermissionNotificationProps = { /** @@ -32,13 +33,13 @@ export const usePermissionNotification = ( const previousHasPermission = usePrevious(hasPermission); const callingState = useCallCallingState(); - const showGrantedNotification = useCallback(() => { + const showGrantedNotification = useEffectEvent(() => { Alert.alert(messageApproved); - }, [messageApproved]); + }); - const showRevokedNotification = useCallback(() => { + const showRevokedNotification = useEffectEvent(() => { Alert.alert(messageRevoked); - }, [messageRevoked]); + }); useEffect(() => { // Permission state is not reliable before the call is joined, @@ -51,11 +52,5 @@ export const usePermissionNotification = ( } else if (!hasPermission && previousHasPermission) { showRevokedNotification(); } - }, [ - callingState, - hasPermission, - previousHasPermission, - showGrantedNotification, - showRevokedNotification, - ]); + }, [callingState, hasPermission, previousHasPermission]); }; diff --git a/packages/react-sdk/src/hooks/useEffectEvent.ts b/packages/react-sdk/src/hooks/useEffectEvent.ts deleted file mode 100644 index 2ac10d6dcb..0000000000 --- a/packages/react-sdk/src/hooks/useEffectEvent.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useCallback, useLayoutEffect, useRef } from 'react'; - -export function useEffectEvent

( - cb: ((...args: P) => void) | undefined, -): (...args: P) => void { - const cbRef = useRef<((...args: P) => void) | undefined>(undefined); - - useLayoutEffect(() => { - cbRef.current = cb; - }, [cb]); - - return useCallback((...args: P) => { - const callback = cbRef.current; - callback?.(...args); - }, []); -} diff --git a/packages/react-sdk/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx b/packages/react-sdk/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx index a54a955294..ba2438c5d9 100644 --- a/packages/react-sdk/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx +++ b/packages/react-sdk/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx @@ -12,7 +12,7 @@ import { LivestreamLayoutProps, StreamCall, } from '../../core'; -import { useEffectEvent } from '../../hooks/useEffectEvent'; +import { useEffectEvent } from '@stream-io/video-react-bindings'; export type LivestreamPlayerProps = { /** @@ -53,7 +53,7 @@ export const LivestreamPlayer = (props: LivestreamPlayerProps) => { const { callType, callId, ...restProps } = props; const client = useStreamVideoClient(); const [call, setCall] = useState(); - const onError = useEffectEvent(props.onError); + const onError = useEffectEvent(props.onError ?? (() => {})); useEffect(() => { if (!client) return; @@ -69,7 +69,7 @@ export const LivestreamPlayer = (props: LivestreamPlayerProps) => { }); setCall(undefined); }; - }, [callId, callType, client, onError]); + }, [callId, callType, client]); if (!call) { return null; @@ -116,7 +116,7 @@ const useLivestreamCall = (props: { const canJoin = (joinBehavior === 'asap' && canJoinAsap) || (joinBehavior === 'live' && canJoinLive); - const onError = useEffectEvent(props.onError); + const onError = useEffectEvent(props.onError ?? (() => {})); useEffect(() => { if (call && call.state.callingState === CallingState.IDLE && canJoin) { @@ -125,7 +125,7 @@ const useLivestreamCall = (props: { onError(e); }); } - }, [call, canJoin, onError]); + }, [call, canJoin]); return call; }; diff --git a/yarn.lock b/yarn.lock index af393998be..e12a454b7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -111,6 +111,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.24.4": + version: 7.28.4 + resolution: "@babel/core@npm:7.28.4" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.3" + "@babel/helper-compilation-targets": "npm:^7.27.2" + "@babel/helper-module-transforms": "npm:^7.28.3" + "@babel/helpers": "npm:^7.28.4" + "@babel/parser": "npm:^7.28.4" + "@babel/template": "npm:^7.27.2" + "@babel/traverse": "npm:^7.28.4" + "@babel/types": "npm:^7.28.4" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/0593295241fac9be567145ef16f3858d34fc91390a9438c6d47476be9823af4cc0488c851c59702dd46b968e9fd46d17ddf0105ea30195ca85f5a66b4044c519 + languageName: node + linkType: hard + "@babel/generator@npm:^7.20.0, @babel/generator@npm:^7.20.5, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.7, @babel/generator@npm:^7.27.1, @babel/generator@npm:^7.7.2": version: 7.27.1 resolution: "@babel/generator@npm:7.27.1" @@ -124,6 +147,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.28.3": + version: 7.28.3 + resolution: "@babel/generator@npm:7.28.3" + dependencies: + "@babel/parser": "npm:^7.28.3" + "@babel/types": "npm:^7.28.2" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10/d00d1e6b51059e47594aab7920b88ec6fcef6489954a9172235ab57ad2e91b39c95376963a6e2e4cc7e8b88fa4f931018f71f9ab32bbc9c0bc0de35a0231f26c + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.25.9, @babel/helper-annotate-as-pure@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-annotate-as-pure@npm:7.27.1" @@ -191,6 +227,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-globals@npm:^7.28.0": + version: 7.28.0 + resolution: "@babel/helper-globals@npm:7.28.0" + checksum: 10/91445f7edfde9b65dcac47f4f858f68dc1661bf73332060ab67ad7cc7b313421099a2bfc4bda30c3db3842cfa1e86fffbb0d7b2c5205a177d91b22c8d7d9cb47 + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-member-expression-to-functions@npm:7.27.1" @@ -224,6 +267,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.28.3": + version: 7.28.3 + resolution: "@babel/helper-module-transforms@npm:7.28.3" + dependencies: + "@babel/helper-module-imports": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.3" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/598fdd8aa5b91f08542d0ba62a737847d0e752c8b95ae2566bc9d11d371856d6867d93e50db870fb836a6c44cfe481c189d8a2b35ca025a224f070624be9fa87 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-optimise-call-expression@npm:7.27.1" @@ -327,6 +383,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/helpers@npm:7.28.4" + dependencies: + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.4" + checksum: 10/5a70a82e196cf8808f8a449cc4780c34d02edda2bb136d39ce9d26e63b615f18e89a95472230c3ce7695db0d33e7026efeee56f6454ed43480f223007ed205eb + languageName: node + linkType: hard + "@babel/highlight@npm:^7.10.4": version: 7.25.7 resolution: "@babel/highlight@npm:7.25.7" @@ -350,6 +416,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.4, @babel/parser@npm:^7.28.3, @babel/parser@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/parser@npm:7.28.4" + dependencies: + "@babel/types": "npm:^7.28.4" + bin: + parser: ./bin/babel-parser.js + checksum: 10/f54c46213ef180b149f6a17ea765bf40acc1aebe2009f594e2a283aec69a190c6dda1fdf24c61a258dbeb903abb8ffb7a28f1a378f8ab5d333846ce7b7e23bf1 + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.27.1" @@ -472,6 +549,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-proposal-private-methods@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad + languageName: node + linkType: hard + "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": version: 7.21.0-placeholder-for-preset-env.2 resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" @@ -1583,7 +1672,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.0.0, @babel/template@npm:^7.25.0, @babel/template@npm:^7.25.7, @babel/template@npm:^7.27.1, @babel/template@npm:^7.3.3": +"@babel/template@npm:^7.0.0, @babel/template@npm:^7.25.0, @babel/template@npm:^7.25.7, @babel/template@npm:^7.27.1, @babel/template@npm:^7.27.2, @babel/template@npm:^7.3.3": version: 7.27.2 resolution: "@babel/template@npm:7.27.2" dependencies: @@ -1624,6 +1713,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4": + version: 7.28.4 + resolution: "@babel/traverse@npm:7.28.4" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.3" + "@babel/helper-globals": "npm:^7.28.0" + "@babel/parser": "npm:^7.28.4" + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.4" + debug: "npm:^4.3.1" + checksum: 10/c3099364b7b1c36bcd111099195d4abeef16499e5defb1e56766b754e8b768c252e856ed9041665158aa1b31215fc6682632756803c8fa53405381ec08c4752b + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.4, @babel/types@npm:^7.25.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.27.1, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": version: 7.27.1 resolution: "@babel/types@npm:7.27.1" @@ -1634,7 +1738,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.26.0": +"@babel/types@npm:^7.26.0, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4": version: 7.28.4 resolution: "@babel/types@npm:7.28.4" dependencies: @@ -4677,6 +4781,26 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.12": + version: 0.3.13 + resolution: "@jridgewell/gen-mapping@npm:0.3.13" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10/902f8261dcf450b4af7b93f9656918e02eec80a2169e155000cb2059f90113dd98f3ccf6efc6072cee1dd84cac48cade51da236972d942babc40e4c23da4d62a + languageName: node + linkType: hard + +"@jridgewell/remapping@npm:^2.3.5": + version: 2.3.5 + resolution: "@jridgewell/remapping@npm:2.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10/c2bb01856e65b506d439455f28aceacf130d6c023d1d4e3b48705e88def3571753e1a887daa04b078b562316c92d26ce36408a60534bceca3f830aec88a339ad + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.1 resolution: "@jridgewell/resolve-uri@npm:3.1.1" @@ -4718,6 +4842,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.28": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10/da0283270e691bdb5543806077548532791608e52386cfbbf3b9e8fb00457859d1bd01d512851161c886eb3a2f3ce6fd9bcf25db8edf3bddedd275bd4a88d606 + languageName: node + linkType: hard + "@jscutlery/semver@npm:^5.6.0": version: 5.6.0 resolution: "@jscutlery/semver@npm:5.6.0" @@ -8599,7 +8733,7 @@ __metadata: eslint: "npm:^9.26.0" eslint-plugin-import: "npm:^2.31.0" eslint-plugin-react: "npm:^7.37.5" - eslint-plugin-react-hooks: "npm:^5.2.0" + eslint-plugin-react-hooks: "npm:^6.1.0" globals: "npm:^16.1.0" husky: "npm:^9.1.7" lint-staged: "npm:^15.5.2" @@ -8617,7 +8751,7 @@ __metadata: dependencies: "@rollup/plugin-typescript": "npm:^12.1.2" "@stream-io/video-client": "workspace:^" - "@types/react": "npm:^19.1.3" + "@types/react": "npm:^19.2.0" i18next: "npm:^25.2.1" react: "npm:19.0.0" rimraf: "npm:^6.0.1" @@ -9400,11 +9534,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^19.1.3": - version: 19.1.3 - resolution: "@types/react-dom@npm:19.1.3" + version: 19.2.0 + resolution: "@types/react-dom@npm:19.2.0" peerDependencies: - "@types/react": ^19.0.0 - checksum: 10/e951e683ee5fd823e938a847372cdc161b8f15a88dd80b54b2d6fe9fa189862412e584609aca9355835c388a528b6e71283e7dc13071b22f75bdc4fa676a3b56 + "@types/react": ^19.2.0 + checksum: 10/e1e2e71214af67e1aa433a25b5f193d8bc98bfc16e108783c2c45c520623737af3c91ee929124c1f7adf2c3988bbd493cdc4ff64af69731245a3a758fde82291 languageName: node linkType: hard @@ -9452,7 +9586,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:>=16.0.0, @types/react@npm:^19.1.3": +"@types/react@npm:*, @types/react@npm:>=16.0.0": version: 19.1.3 resolution: "@types/react@npm:19.1.3" dependencies: @@ -9461,12 +9595,21 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^19.1.3, @types/react@npm:^19.2.0": + version: 19.2.0 + resolution: "@types/react@npm:19.2.0" + dependencies: + csstype: "npm:^3.0.2" + checksum: 10/c00a8552d54282caeb608d09664a250e6bd00b1f51e32bb73a0569d844ddbf58d25ffadffec85cc5df08e6c00e6c232a06a8efcfa5edd0bea2ce234519707b34 + languageName: node + linkType: hard + "@types/react@npm:~19.1.10": - version: 19.1.13 - resolution: "@types/react@npm:19.1.13" + version: 19.1.17 + resolution: "@types/react@npm:19.1.17" dependencies: csstype: "npm:^3.0.2" - checksum: 10/a4e12df335ded76e931cc2ba2a4c8a61872ed840081eca83612fbdadc4afbf0cbd0ae31fdedc7fae7f0e02c90dac98dda517dfa73bec653dd4b1de2755431a62 + checksum: 10/b21d0ce3296e758e0bbbaa177bea0ed2d7c6a08810d3889d2e7777b2d7ff76d9454690b964883ce2c9d3da73412380dd6cff05794cbd54890e0ef1f3c4b4332d languageName: node linkType: hard @@ -13503,12 +13646,19 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^5.2.0": - version: 5.2.0 - resolution: "eslint-plugin-react-hooks@npm:5.2.0" +"eslint-plugin-react-hooks@npm:^6.1.0": + version: 6.1.0 + resolution: "eslint-plugin-react-hooks@npm:6.1.0" + dependencies: + "@babel/core": "npm:^7.24.4" + "@babel/parser": "npm:^7.24.4" + "@babel/plugin-proposal-private-methods": "npm:^7.18.6" + hermes-parser: "npm:^0.25.1" + zod: "npm:^3.22.4" + zod-validation-error: "npm:^3.0.3" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - checksum: 10/ebb79e9cf69ae06e3a7876536653c5e556b5fd8cd9dc49577f10a6e728360e7b6f5ce91f4339b33e93b26e3bb23805418f8b5e75db80baddd617b1dffe73bed1 + checksum: 10/0b1d32510f6419c058182ec159914f6580bb070bbabcdb1ac47348993f84c3c93407304b93de13920b1a6e5bf72463367ab80d9e5aa688f3e44000abab75fa14 languageName: node linkType: hard @@ -15914,7 +16064,7 @@ __metadata: languageName: node linkType: hard -"hermes-parser@npm:0.25.1": +"hermes-parser@npm:0.25.1, hermes-parser@npm:^0.25.1": version: 0.25.1 resolution: "hermes-parser@npm:0.25.1" dependencies: @@ -27835,20 +27985,29 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.23.8, zod@npm:^3.24.2": - version: 3.24.4 - resolution: "zod@npm:3.24.4" - checksum: 10/3d545792fa54bb27ee5dbc34a5709e81f603185fcc94c8204b5d95c20dc4c81d870ff9c51f3884a30ef05cdc601449f4c4df254ac4783f0827b1faed7c1cdb48 +"zod-validation-error@npm:^3.0.3": + version: 3.5.3 + resolution: "zod-validation-error@npm:3.5.3" + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + checksum: 10/f550565ffb2a0a1733616d856302184dbe2080ec649ff9361125467065c3dfa02aeb5bf399605cdb61fe640f79ff1fe8ad0805f6e0c8144fa34764cad58f4401 languageName: node linkType: hard -"zod@npm:^3.25.76": +"zod@npm:^3.22.4, zod@npm:^3.25.76": version: 3.25.76 resolution: "zod@npm:3.25.76" checksum: 10/f0c963ec40cd96858451d1690404d603d36507c1fc9682f2dae59ab38b578687d542708a7fdbf645f77926f78c9ed558f57c3d3aa226c285f798df0c4da16995 languageName: node linkType: hard +"zod@npm:^3.23.8, zod@npm:^3.24.2": + version: 3.24.4 + resolution: "zod@npm:3.24.4" + checksum: 10/3d545792fa54bb27ee5dbc34a5709e81f603185fcc94c8204b5d95c20dc4c81d870ff9c51f3884a30ef05cdc601449f4c4df254ac4783f0827b1faed7c1cdb48 + languageName: node + linkType: hard + "zwitch@npm:^2.0.0": version: 2.0.4 resolution: "zwitch@npm:2.0.4"