diff --git a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx index bd5e9b2c0..d30da2fef 100644 --- a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx +++ b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx @@ -1,4 +1,4 @@ -import { FormEvent, useEffect } from 'react'; +import { FormEvent, memo, useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import { Button, @@ -25,8 +25,9 @@ interface EditFormDrawerProps { viewOptions: ViewOption[]; } -// TODO: this is a good candidate for memoisation, but needs the paramFields to be stable -export default function ViewParamsEditor({ viewOptions }: EditFormDrawerProps) { +export default memo(ViewParamsEditor); + +function ViewParamsEditor({ viewOptions }: EditFormDrawerProps) { const [searchParams, setSearchParams] = useSearchParams(); const { data: viewSettings } = useViewSettings(); diff --git a/apps/client/src/features/operator/Operator.tsx b/apps/client/src/features/operator/Operator.tsx index 1298abcee..57d8abf44 100644 --- a/apps/client/src/features/operator/Operator.tsx +++ b/apps/client/src/features/operator/Operator.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { isOntimeEvent, OntimeEvent, SupportedEntry } from 'ontime-types'; import { getFirstEventNormal, getLastEventNormal } from 'ontime-utils'; @@ -107,6 +107,10 @@ export default function Operator() { const missingData = !data || !customFields || !projectData; const isLoading = status === 'pending' || customFieldStatus === 'pending' || projectDataStatus === 'pending'; + // gather option data + const defaultFormat = getDefaultFormat(settings?.timeFormat); + const operatorOptions = useMemo(() => getOperatorOptions(customFields, defaultFormat), [customFields, defaultFormat]); + if (missingData || isLoading) { return ; } @@ -121,8 +125,6 @@ export default function Operator() { const main = searchParams.get('main') as keyof TitleFields | null; const secondary = searchParams.get('secondary'); - const defaultFormat = getDefaultFormat(settings?.timeFormat); - const operatorOptions = getOperatorOptions(customFields, defaultFormat); let isPast = Boolean(featureData.selectedEventId); const hidePast = isStringBoolean(searchParams.get('hidepast')); diff --git a/apps/client/src/features/viewers/clock/Clock.tsx b/apps/client/src/features/viewers/clock/Clock.tsx index b0a739cdf..b5454caa3 100644 --- a/apps/client/src/features/viewers/clock/Clock.tsx +++ b/apps/client/src/features/viewers/clock/Clock.tsx @@ -1,3 +1,4 @@ +import { useMemo } from 'react'; import { useSearchParams } from 'react-router-dom'; import { ProjectData, Settings } from 'ontime-types'; @@ -112,7 +113,7 @@ export default function Clock(props: ClockProps) { const clean = clock.replace('/:/g', ''); const defaultFormat = getDefaultFormat(settings?.timeFormat); - const clockOptions = getClockOptions(defaultFormat); + const clockOptions = useMemo(() => getClockOptions(defaultFormat), [defaultFormat]); return (
getLowerThirdOptions(customFields), [customFields]); + return (
- +
getBackstageOptions(defaultFormat, customFields), + [defaultFormat, customFields], + ); return (
diff --git a/apps/client/src/views/countdown/Countdown.tsx b/apps/client/src/views/countdown/Countdown.tsx index 69055f559..4e7db1170 100644 --- a/apps/client/src/views/countdown/Countdown.tsx +++ b/apps/client/src/views/countdown/Countdown.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useMemo, useState } from 'react'; import { IoAdd } from 'react-icons/io5'; import { CustomFields, @@ -63,7 +63,10 @@ export default function Countdown({ // gather option data const defaultFormat = getDefaultFormat(settings?.timeFormat); - const countdownOptions = getCountdownOptions(defaultFormat, customFields, subscriptions); + const countdownOptions = useMemo( + () => getCountdownOptions(defaultFormat, customFields, subscriptions), + [defaultFormat, customFields, subscriptions], + ); return (
diff --git a/apps/client/src/views/timeline/TimelinePage.tsx b/apps/client/src/views/timeline/TimelinePage.tsx index bc444d8b2..1d6980bf2 100644 --- a/apps/client/src/views/timeline/TimelinePage.tsx +++ b/apps/client/src/views/timeline/TimelinePage.tsx @@ -45,7 +45,7 @@ export default function TimelinePage(props: TimelinePageProps) { // populate options const defaultFormat = getDefaultFormat(settings?.timeFormat); - const progressOptions = getTimelineOptions(defaultFormat); + const progressOptions = useMemo(() => getTimelineOptions(defaultFormat), [defaultFormat]); const titleNow = now?.title ?? '-'; const dueText = getLocalizedString('timeline.due').toUpperCase();