mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-25 01:37:30 +00:00
⚡️(frontend) memoize the Placeholder component
Turn the Placeholder into a pure leaf component and memoize it, so it does not re-render on unrelated parent updates when its props have not changed.
This commit is contained in:
@@ -1,10 +1,7 @@
|
|||||||
import type { Participant } from 'livekit-client'
|
|
||||||
import { styled } from '@/styled-system/jsx'
|
import { styled } from '@/styled-system/jsx'
|
||||||
import { Avatar } from '@/components/Avatar'
|
import { Avatar } from '@/components/Avatar'
|
||||||
import { useIsSpeaking } from '@livekit/components-react'
|
|
||||||
import { getParticipantBackgroundGradient } from '@/features/rooms/utils/getParticipantBackgroundGradient'
|
import { getParticipantBackgroundGradient } from '@/features/rooms/utils/getParticipantBackgroundGradient'
|
||||||
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
import React, { useMemo } from 'react'
|
||||||
import { useMemo } from 'react'
|
|
||||||
|
|
||||||
const StyledParticipantPlaceHolder = styled('div', {
|
const StyledParticipantPlaceHolder = styled('div', {
|
||||||
base: {
|
base: {
|
||||||
@@ -23,39 +20,36 @@ const StyledAvatarWrapper = styled('div', {
|
|||||||
aspectRatio: '1 / 1',
|
aspectRatio: '1 / 1',
|
||||||
width: 'min(90cqmin, 160px)',
|
width: 'min(90cqmin, 160px)',
|
||||||
fontSize: 'min(27cqmin, 48px)',
|
fontSize: 'min(27cqmin, 48px)',
|
||||||
|
'[data-lk-speaking="true"] &': {
|
||||||
|
animation: 'pulse 1s infinite',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
type ParticipantPlaceholderProps = {
|
type ParticipantPlaceholderProps = {
|
||||||
participant: Participant
|
color: string
|
||||||
|
displayedNamed: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ParticipantPlaceholder = ({
|
export const ParticipantPlaceholder = React.memo(
|
||||||
participant,
|
({ color, displayedNamed }: ParticipantPlaceholderProps) => {
|
||||||
}: ParticipantPlaceholderProps) => {
|
const backgroundGradient = useMemo(
|
||||||
const isSpeaking = useIsSpeaking(participant)
|
() => getParticipantBackgroundGradient(color),
|
||||||
const participantColor = getParticipantColor(participant)
|
[color]
|
||||||
const backgroundGradient = useMemo(
|
)
|
||||||
() => getParticipantBackgroundGradient(participantColor),
|
return (
|
||||||
[participantColor]
|
<StyledParticipantPlaceHolder
|
||||||
)
|
style={{
|
||||||
|
backgroundColor: color,
|
||||||
return (
|
backgroundImage: backgroundGradient,
|
||||||
<StyledParticipantPlaceHolder
|
}}
|
||||||
style={{
|
|
||||||
backgroundColor: participantColor,
|
|
||||||
backgroundImage: backgroundGradient,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<StyledAvatarWrapper
|
|
||||||
style={{ animation: isSpeaking ? 'pulse 1s infinite' : undefined }}
|
|
||||||
>
|
>
|
||||||
<Avatar
|
<StyledAvatarWrapper>
|
||||||
name={participant.name}
|
<Avatar name={displayedNamed} bgColor={color} context="placeholder" />
|
||||||
bgColor={participantColor}
|
</StyledAvatarWrapper>
|
||||||
context="placeholder"
|
</StyledParticipantPlaceHolder>
|
||||||
/>
|
)
|
||||||
</StyledAvatarWrapper>
|
}
|
||||||
</StyledParticipantPlaceHolder>
|
)
|
||||||
)
|
|
||||||
}
|
ParticipantPlaceholder.displayName = 'ParticipantPlaceholder'
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
AudioTrack,
|
AudioTrack,
|
||||||
ParticipantTileProps,
|
ParticipantTileProps,
|
||||||
@@ -9,7 +10,6 @@ import {
|
|||||||
TrackRefContext,
|
TrackRefContext,
|
||||||
ParticipantContextIfNeeded,
|
ParticipantContextIfNeeded,
|
||||||
} from '@livekit/components-react'
|
} from '@livekit/components-react'
|
||||||
import React from 'react'
|
|
||||||
import {
|
import {
|
||||||
isEqualTrackRef,
|
isEqualTrackRef,
|
||||||
isTrackReference,
|
isTrackReference,
|
||||||
@@ -26,6 +26,7 @@ import { formatShortcutLabel } from '@/features/shortcuts/formatLabels'
|
|||||||
import { KeyboardShortcutHint } from './KeyboardShortcutHint'
|
import { KeyboardShortcutHint } from './KeyboardShortcutHint'
|
||||||
import { layoutStore, clearPinnedTrack } from '@/stores/layout'
|
import { layoutStore, clearPinnedTrack } from '@/stores/layout'
|
||||||
import { ParticipantMetadata } from './ParticipantMetadata'
|
import { ParticipantMetadata } from './ParticipantMetadata'
|
||||||
|
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
||||||
|
|
||||||
export function TrackRefContextIfNeeded(
|
export function TrackRefContextIfNeeded(
|
||||||
props: React.PropsWithChildren<{
|
props: React.PropsWithChildren<{
|
||||||
@@ -90,6 +91,8 @@ export const ParticipantTile: (
|
|||||||
const isScreenShare = trackReference.source != Track.Source.Camera
|
const isScreenShare = trackReference.source != Track.Source.Camera
|
||||||
const [hasKeyboardFocus, setHasKeyboardFocus] = React.useState(false)
|
const [hasKeyboardFocus, setHasKeyboardFocus] = React.useState(false)
|
||||||
|
|
||||||
|
const participantColor = getParticipantColor(trackReference.participant)
|
||||||
|
|
||||||
const participantName = getParticipantName(trackReference.participant)
|
const participantName = getParticipantName(trackReference.participant)
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
|
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
|
||||||
|
|
||||||
@@ -141,7 +144,11 @@ export const ParticipantTile: (
|
|||||||
)}
|
)}
|
||||||
<div className="lk-participant-placeholder">
|
<div className="lk-participant-placeholder">
|
||||||
<ParticipantPlaceholder
|
<ParticipantPlaceholder
|
||||||
participant={trackReference.participant}
|
color={participantColor}
|
||||||
|
displayedNamed={
|
||||||
|
trackReference.participant.name ||
|
||||||
|
trackReference.participant.identity
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!disableMetadata && (
|
{!disableMetadata && (
|
||||||
|
|||||||
Reference in New Issue
Block a user