fix(striker-ui): avoid unneeded recreation of message setters

main
Tsu-ba-me 2 years ago
parent b99ac243ab
commit 23ea09ed35
  1. 7
      striker-ui/components/ManageManifest/AnHostInputGroup.tsx
  2. 11
      striker-ui/components/ManageManifest/AnNetworkInputGroup.tsx
  3. 4
      striker-ui/components/ManageManifest/RunManifestInputGroup.tsx
  4. 58
      striker-ui/hooks/useFormUtils.ts
  5. 41
      striker-ui/lib/buildObjectStateSetterCallback.ts
  6. 23
      striker-ui/types/BuildObjectStateSetterCallback.d.ts
  7. 2
      striker-ui/types/FormUtils.d.ts

@ -110,7 +110,6 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
msgSetters, msgSetters,
setMsgSetter,
}, },
hostId, hostId,
hostNumber, hostNumber,
@ -152,8 +151,6 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
const inputId = buildInputIdAHFencePort(hostId, fenceId); const inputId = buildInputIdAHFencePort(hostId, fenceId);
const inputLabel = `Port on ${fenceName}`; const inputLabel = `Port on ${fenceName}`;
setMsgSetter(inputId);
previous[cellId] = { previous[cellId] = {
children: ( children: (
<InputWithRef <InputWithRef
@ -196,7 +193,6 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
fenceListEntries, fenceListEntries,
hostId, hostId,
msgSetters, msgSetters,
setMsgSetter,
], ],
); );
@ -209,8 +205,6 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
const inputId = buildInputIdAHNetworkIp(hostId, networkId); const inputId = buildInputIdAHNetworkIp(hostId, networkId);
const inputLabel = `${NETWORK_TYPES[networkType]} ${networkNumber}`; const inputLabel = `${NETWORK_TYPES[networkType]} ${networkNumber}`;
setMsgSetter(inputId);
previous[cellId] = { previous[cellId] = {
children: ( children: (
<InputWithRef <InputWithRef
@ -251,7 +245,6 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
[ [
networkListEntries, networkListEntries,
hostId, hostId,
setMsgSetter,
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
msgSetters, msgSetters,

@ -1,4 +1,4 @@
import { ReactElement, ReactNode, useEffect, useMemo } from 'react'; import { ReactElement, ReactNode, useMemo } from 'react';
import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES'; import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES';
@ -81,7 +81,6 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
msgSetters, msgSetters,
setMsgSetter,
}, },
inputGatewayLabel = 'Gateway', inputGatewayLabel = 'Gateway',
inputMinIpLabel = 'IP address', inputMinIpLabel = 'IP address',
@ -170,8 +169,6 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
let result: ReactNode; let result: ReactNode;
if (isShowGateway && inputIdGateway) { if (isShowGateway && inputIdGateway) {
setMsgSetter(inputIdGateway);
result = ( result = (
<InputWithRef <InputWithRef
input={ input={
@ -209,7 +206,6 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
}, [ }, [
isShowGateway, isShowGateway,
inputIdGateway, inputIdGateway,
setMsgSetter,
networkId, networkId,
inputGatewayLabel, inputGatewayLabel,
previousGateway, previousGateway,
@ -219,11 +215,6 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
msgSetters, msgSetters,
]); ]);
useEffect(() => {
setMsgSetter(inputIdMinIp);
setMsgSetter(inputIdSubnetMask);
}, [inputIdMinIp, inputIdSubnetMask, setMsgSetter]);
return ( return (
<InnerPanel mv={0}> <InnerPanel mv={0}>
<InnerPanelHeader> <InnerPanelHeader>

@ -36,7 +36,6 @@ const RunManifestInputGroup = <M extends MapToInputTestID>({
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
msgSetters, msgSetters,
setMsgSetter,
}, },
knownFences = {}, knownFences = {},
knownHosts = {}, knownHosts = {},
@ -104,8 +103,6 @@ const RunManifestInputGroup = <M extends MapToInputTestID>({
const inputId = buildInputIdRMHost(hostId); const inputId = buildInputIdRMHost(hostId);
const inputLabel = `${prettyId} host`; const inputLabel = `${prettyId} host`;
setMsgSetter(inputId);
hosts[`run-manifest-host-cell-${hostId}`] = { hosts[`run-manifest-host-cell-${hostId}`] = {
children: ( children: (
<InputWithRef <InputWithRef
@ -166,7 +163,6 @@ const RunManifestInputGroup = <M extends MapToInputTestID>({
hostListEntries, hostListEntries,
hostOptionList, hostOptionList,
msgSetters, msgSetters,
setMsgSetter,
], ],
); );

@ -3,7 +3,9 @@ import { MutableRefObject, useCallback, useMemo, useState } from 'react';
import buildMapToMessageSetter, { import buildMapToMessageSetter, {
buildMessageSetter, buildMessageSetter,
} from '../lib/buildMapToMessageSetter'; } from '../lib/buildMapToMessageSetter';
import buildObjectStateSetterCallback from '../lib/buildObjectStateSetterCallback'; import buildObjectStateSetterCallback, {
buildProtectedObjectStateSetterCallback,
} from '../lib/buildObjectStateSetterCallback';
import { MessageGroupForwardedRefContent } from '../components/MessageGroup'; import { MessageGroupForwardedRefContent } from '../components/MessageGroup';
const useFormUtils = < const useFormUtils = <
@ -15,6 +17,9 @@ const useFormUtils = <
messageGroupRef: MutableRefObject<MessageGroupForwardedRefContent>, messageGroupRef: MutableRefObject<MessageGroupForwardedRefContent>,
): FormUtils<M> => { ): FormUtils<M> => {
const [formValidity, setFormValidity] = useState<FormValidity<M>>({}); const [formValidity, setFormValidity] = useState<FormValidity<M>>({});
const [msgSetterList, setMsgSetterList] = useState<MapToMessageSetter<M>>(
() => buildMapToMessageSetter<U, I, M>(ids, messageGroupRef),
);
const setValidity = useCallback((key: keyof M, value?: boolean) => { const setValidity = useCallback((key: keyof M, value?: boolean) => {
setFormValidity( setFormValidity(
@ -42,6 +47,37 @@ const useFormUtils = <
}); });
}, []); }, []);
const setMsgSetter = useCallback(
(
id: keyof M,
setter?: MessageSetter,
{
isOverwrite,
isUseFallback = true,
}: { isOverwrite?: boolean; isUseFallback?: boolean } = {},
) => {
const fallbackSetter: ObjectStatePropSetter<MapToMessageSetter<M>> = (
result,
key,
value = buildMessageSetter<M>(String(id), messageGroupRef),
) => {
result[key] = value;
};
setMsgSetterList(
buildProtectedObjectStateSetterCallback<MapToMessageSetter<M>>(
id,
setter,
{
isOverwrite,
set: isUseFallback ? fallbackSetter : undefined,
},
),
);
},
[messageGroupRef],
);
const buildFinishInputTestBatchFunction = useCallback( const buildFinishInputTestBatchFunction = useCallback(
(key: keyof M) => (result: boolean) => { (key: keyof M) => (result: boolean) => {
setValidity(key, result); setValidity(key, result);
@ -52,9 +88,10 @@ const useFormUtils = <
const buildInputFirstRenderFunction = useCallback( const buildInputFirstRenderFunction = useCallback(
(key: keyof M) => (key: keyof M) =>
({ isValid }: InputFirstRenderFunctionArgs) => { ({ isValid }: InputFirstRenderFunctionArgs) => {
setMsgSetter(key);
setValidity(key, isValid); setValidity(key, isValid);
}, },
[setValidity], [setMsgSetter, setValidity],
); );
const isFormInvalid = useMemo( const isFormInvalid = useMemo(
@ -62,27 +99,12 @@ const useFormUtils = <
[formValidity], [formValidity],
); );
const msgSetters = useMemo(
() => buildMapToMessageSetter<U, I, M>(ids, messageGroupRef),
[ids, messageGroupRef],
);
const setMsgSetter = useCallback(
(id: keyof M, setter?: MessageSetter, isOverwrite?: boolean) => {
if (!msgSetters[id] || isOverwrite) {
msgSetters[id] =
setter ?? buildMessageSetter<M>(String(id), messageGroupRef);
}
},
[messageGroupRef, msgSetters],
);
return { return {
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
formValidity, formValidity,
isFormInvalid, isFormInvalid,
msgSetters, msgSetters: msgSetterList,
setFormValidity, setFormValidity,
setMsgSetter, setMsgSetter,
setValidity, setValidity,

@ -1,13 +1,46 @@
/**
* Checks whether specified `key` is unset in given object. Always returns
* `true` when overwrite is allowed.
*/
const checkUnset = <S extends BaseObject>(
obj: S,
key: keyof S,
{ isOverwrite = false }: { isOverwrite?: boolean } = {},
): boolean => !(key in obj) || isOverwrite;
const buildObjectStateSetterCallback = const buildObjectStateSetterCallback =
<S extends Record<string, unknown>>(key: keyof S, value?: S[keyof S]) => <S extends BaseObject>(
({ [key]: toReplace, ...restPrevious }: S): S => { key: keyof S,
value?: S[keyof S],
{
guard,
set = (o, k, v) => {
if (v !== undefined) {
o[k] = v;
}
},
}: BuildObjectStateSetterCallbackOptions<S> = {},
): BuildObjectStateSetterCallbackReturnType<S> =>
(previous: S): S => {
const { [key]: toReplace, ...restPrevious } = previous;
const result = { ...restPrevious } as S; const result = { ...restPrevious } as S;
if (value !== undefined) { if (guard?.call(null, previous, key, value)) {
result[key] = value; set(result, key, value);
} }
return result; return result;
}; };
export const buildProtectedObjectStateSetterCallback = <S extends BaseObject>(
key: keyof S,
value?: S[keyof S],
{
isOverwrite,
guard = (o, k) => checkUnset(o, k, { isOverwrite }),
set,
}: BuildObjectStateSetterCallbackOptions<S> = {},
): BuildObjectStateSetterCallbackReturnType<S> =>
buildObjectStateSetterCallback(key, value, { isOverwrite, guard, set });
export default buildObjectStateSetterCallback; export default buildObjectStateSetterCallback;

@ -0,0 +1,23 @@
type BaseObject<T = unknown> = Record<number | string | symbol, T>;
type ObjectStatePropGuard<S extends BaseObject> = (
previous: S,
key: keyof S,
value?: S[keyof S],
) => boolean;
type ObjectStatePropSetter<S extends BaseObject> = (
result: S,
key: keyof S,
value?: S[keyof S],
) => void;
type BuildObjectStateSetterCallbackOptions<S extends BaseObject> = {
guard?: ObjectStatePropGuard<S>;
isOverwrite?: boolean;
set?: ObjectStatePropSetter<S>;
};
type BuildObjectStateSetterCallbackReturnType<S extends BaseObject> = (
previous: S,
) => S;

@ -26,7 +26,7 @@ type FormUtils<M extends MapToInputTestID> = {
setMsgSetter: ( setMsgSetter: (
id: keyof M, id: keyof M,
setter?: MessageSetter, setter?: MessageSetter,
isOverwrite?: boolean, options?: { isOverwrite?: boolean },
) => void; ) => void;
setValidity: (key: keyof M, value?: boolean) => void; setValidity: (key: keyof M, value?: boolean) => void;
setValidityRe: (re: RegExp, value?: boolean) => void; setValidityRe: (re: RegExp, value?: boolean) => void;

Loading…
Cancel
Save