refactor: stabilise actionHandler (#683)

This commit is contained in:
Carlos Valente
2023-12-30 21:13:51 +01:00
committed by GitHub
parent 3998b8927d
commit 5409c0ac6e
3 changed files with 111 additions and 88 deletions
@@ -13,6 +13,7 @@ export const RUNTIME = ['runtimeStore'];
const location = window.location; const location = window.location;
const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws'; const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
export const isProduction = import.meta.env.MODE === 'production'; export const isProduction = import.meta.env.MODE === 'production';
export const isDev = !isProduction;
const STATIC_PORT = 4001; const STATIC_PORT = 4001;
export const serverPort = isProduction ? location.port : STATIC_PORT; export const serverPort = isProduction ? location.port : STATIC_PORT;
@@ -0,0 +1,38 @@
/**
* Shamelessly from https://ahooks.js.org/hooks/use-memoized-fn/
* Interesting technique discussed by Dan Abramov
* https://overreacted.io/making-setinterval-declarative-with-react-hooks/
*/
import { useMemo, useRef } from 'react';
import { isDev } from '../api/apiConstants';
type noop = (this: any, ...args: any[]) => any;
type PickFunction<T extends noop> = (this: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<T>;
export const isFunction = (value: unknown): value is (...args: any) => any => typeof value === 'function';
export default function useMemoisedFn<T extends noop>(fn: T) {
if (isDev) {
if (!isFunction(fn)) {
console.error(`useMemoisedFn expected function as parameter, got ${typeof fn}`);
}
}
const fnRef = useRef<T>(fn);
// why not write `fnRef.current = fn`?
// https://github.com/alibaba/hooks/issues/728
fnRef.current = useMemo(() => fn, [fn]);
const memoizedFn = useRef<PickFunction<T>>();
if (!memoizedFn.current) {
memoizedFn.current = function (this, ...args) {
return fnRef.current.apply(this, args);
};
}
return memoizedFn.current as T;
}
@@ -4,6 +4,7 @@ import { calculateDuration, getCueCandidate } from 'ontime-utils';
import { RUNDOWN } from '../../common/api/apiConstants'; import { RUNDOWN } from '../../common/api/apiConstants';
import { useEventAction } from '../../common/hooks/useEventAction'; import { useEventAction } from '../../common/hooks/useEventAction';
import useMemoisedFn from '../../common/hooks/useMemoisedFn';
import { ontimeQueryClient } from '../../common/queryClient'; import { ontimeQueryClient } from '../../common/queryClient';
import { useAppMode } from '../../common/stores/appModeStore'; import { useAppMode } from '../../common/stores/appModeStore';
import { useEditorSettings } from '../../common/stores/editorSettings'; import { useEditorSettings } from '../../common/stores/editorSettings';
@@ -61,10 +62,7 @@ export default function RundownEntry(props: RundownEntryProps) {
value: unknown; value: unknown;
}; };
// we assume the data is not changing in the lifecycle of this component const actionHandler = useMemoisedFn((action: EventItemActions, payload?: number | FieldValue) => {
// changes to the data would make rundown re-render, also re-rendering this component
const actionHandler = useCallback(
(action: EventItemActions, payload?: number | FieldValue) => {
switch (action) { switch (action) {
case 'event': { case 'event': {
const newEvent = { type: SupportedEvent.Event }; const newEvent = { type: SupportedEvent.Event };
@@ -100,7 +98,7 @@ export default function RundownEntry(props: RundownEntryProps) {
} }
case 'clone': { case 'clone': {
const newEvent = cloneEvent(data as OntimeEvent, data.id); const newEvent = cloneEvent(data as OntimeEvent, data.id);
const rundown = ontimeQueryClient.getQueryData<GetRundownCached>(RUNDOWN)?.rundown ?? [] const rundown = ontimeQueryClient.getQueryData<GetRundownCached>(RUNDOWN)?.rundown ?? [];
newEvent.cue = getCueCandidate(rundown, data.id); newEvent.cue = getCueCandidate(rundown, data.id);
addEvent(newEvent); addEvent(newEvent);
break; break;
@@ -135,21 +133,7 @@ export default function RundownEntry(props: RundownEntryProps) {
default: default:
throw new Error(`Unhandled event ${action}`); throw new Error(`Unhandled event ${action}`);
} }
}, });
[
addEvent,
data,
defaultPublic,
deleteEvent,
emitError,
openId,
previousEventId,
removeOpenEvent,
startTimeIsLastEnd,
updateEvent,
swapEvents,
],
);
if (data.type === SupportedEvent.Event) { if (data.type === SupportedEvent.Event) {
return ( return (