️(frontend) avoid subscribing to full local participant changes

Subscribing to the whole local participant caused re-renders on
every local participant update, even when the consumer only cared
about a specific attribute.

Narrow the subscription so only the relevant attributes trigger a
re-render.
This commit is contained in:
lebaudantoine
2026-07-16 11:39:55 +02:00
committed by aleb_the_flash
parent d2e13cc826
commit 97a9735c0b
3 changed files with 14 additions and 10 deletions
@@ -3,10 +3,10 @@ import { Button, Text } from '@/primitives'
import { useCallback, useMemo, useRef } from 'react' import { useCallback, useMemo, useRef } from 'react'
import { screenSharePreferenceStore } from '@/stores/screenSharePreferences' import { screenSharePreferenceStore } from '@/stores/screenSharePreferences'
import { useSnapshot } from 'valtio' import { useSnapshot } from 'valtio'
import { useLocalParticipant } from '@livekit/components-react'
import type { TrackReferenceOrPlaceholder } from '@livekit/components-core' import type { TrackReferenceOrPlaceholder } from '@livekit/components-core'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSize } from '@/features/rooms/livekit/hooks/useResizeObserver' import { useSize } from '@/features/rooms/livekit/hooks/useResizeObserver'
import { LocalParticipant } from 'livekit-client'
export const FullScreenShareWarning = ({ export const FullScreenShareWarning = ({
trackReference, trackReference,
@@ -17,7 +17,6 @@ export const FullScreenShareWarning = ({
const warningContainerRef = useRef<HTMLDivElement>(null) const warningContainerRef = useRef<HTMLDivElement>(null)
const { width: containerWidth } = useSize(warningContainerRef) const { width: containerWidth } = useSize(warningContainerRef)
const { localParticipant } = useLocalParticipant()
const screenSharePreferences = useSnapshot(screenSharePreferenceStore) const screenSharePreferences = useSnapshot(screenSharePreferenceStore)
const isFullScreenSharing = useMemo(() => { const isFullScreenSharing = useMemo(() => {
@@ -57,8 +56,10 @@ export const FullScreenShareWarning = ({
screenSharePreferences.enabled && isFullScreenSharing screenSharePreferences.enabled && isFullScreenSharing
const handleStopScreenShare = async () => { const handleStopScreenShare = async () => {
if (!localParticipant.isScreenShareEnabled) return const participant = trackReference.participant
await localParticipant.setScreenShareEnabled(false, {}, {}) if (!(participant instanceof LocalParticipant)) return
if (!participant.isScreenShareEnabled) return
await (participant as LocalParticipant).setScreenShareEnabled(false, {}, {})
} }
const handleDismissWarning = useCallback(() => { const handleDismissWarning = useCallback(() => {
@@ -1,18 +1,21 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { styled } from '@/styled-system/jsx' import { styled } from '@/styled-system/jsx'
import { useLocalParticipant } from '@livekit/components-react' import { useTrackToggle } from '@livekit/components-react'
import { Track } from 'livekit-client'
export const StageFrame = ({ children }: { children: React.ReactNode }) => { export const StageFrame = ({ children }: { children: React.ReactNode }) => {
const { t } = useTranslation('rooms', { const { t } = useTranslation('rooms', {
keyPrefix: 'pictureInPicture', keyPrefix: 'pictureInPicture',
}) })
const { localParticipant } = useLocalParticipant() const { enabled: isScreenSharing } = useTrackToggle({
source: Track.Source.ScreenShare,
})
return ( return (
<Container <Container
role="region" role="region"
aria-label={t('stage')} aria-label={t('stage')}
{...(!localParticipant.isScreenShareEnabled ? { inert: '' } : {})} {...(!isScreenSharing ? { inert: '' } : {})}
> >
{children} {children}
</Container> </Container>
@@ -9,8 +9,8 @@ import useLongPress from '@/features/shortcuts/useLongPress'
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker' import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
import { import {
useIsSpeaking, useIsSpeaking,
useLocalParticipant,
useMaybeRoomContext, useMaybeRoomContext,
useRoomContext,
} from '@livekit/components-react' } from '@livekit/components-react'
import type { ButtonRecipeProps } from '@/primitives/buttonRecipe' import type { ButtonRecipeProps } from '@/primitives/buttonRecipe'
import type { ToggleButtonProps } from '@/primitives/ToggleButton' import type { ToggleButtonProps } from '@/primitives/ToggleButton'
@@ -169,7 +169,7 @@ export const ToggleDevice = <T extends ToggleSource>({
} }
const ActiveSpeakerWrapper = () => { const ActiveSpeakerWrapper = () => {
const { localParticipant } = useLocalParticipant() const room = useRoomContext()
const isSpeaking = useIsSpeaking(localParticipant) const isSpeaking = useIsSpeaking(room.localParticipant)
return <ActiveSpeaker isSpeaking={isSpeaking} pushToTalk /> return <ActiveSpeaker isSpeaking={isSpeaking} pushToTalk />
} }