added keys to components when added to an array so react knows what was added and removed correctly w/ burnettk (#1180)

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2024-03-07 13:31:58 -05:00 committed by GitHub
parent ca9a7d9224
commit 5114e99f99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 18 deletions

View File

@ -1,6 +1,6 @@
import { Buffer } from 'buffer';
import { ProcessInstance } from './interfaces';
import { ElementForArray, ProcessInstance } from './interfaces';
export const DEFAULT_PER_PAGE = 50;
export const DEFAULT_PAGE = 1;
@ -300,3 +300,13 @@ export const isURL = (str: string) => {
/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i;
return urlRegex.test(str);
};
// this will help maintain order when using an array of elements.
// React needs to have a key for each component to ensure correct elements are added
// and removed when that array is changed.
// https://stackoverflow.com/questions/46735483/error-do-not-use-array-index-in-keys/46735689#46735689
export const renderElementsForArray = (elements: ElementForArray[]) => {
return elements.map((element: any) => (
<div key={element.key}>{element.component}</div>
));
};

View File

@ -1,3 +1,5 @@
import { ReactElement } from 'react';
export interface User {
id: number;
username: string;
@ -496,3 +498,8 @@ export interface SpiffTableHeader {
tooltip_text?: string;
text: string;
}
export interface ElementForArray {
key: string;
component: ReactElement | null;
}

View File

@ -10,10 +10,12 @@ import {
doNothing,
modifyProcessIdentifierForPathParam,
recursivelyChangeNullAndUndefined,
renderElementsForArray,
setPageTitle,
} from '../helpers';
import {
BasicTask,
ElementForArray,
ErrorForDisplay,
EventDefinition,
HotCrumbItem,
@ -446,7 +448,7 @@ export default function TaskShow() {
);
};
const pageElements = [];
const pageElements: ElementForArray[] = [];
if (basicTask) {
let statusString = '';
if (basicTask.state !== 'READY') {
@ -457,28 +459,38 @@ export default function TaskShow() {
!('allowGuest' in basicTask.extensions) ||
basicTask.extensions.allowGuest !== 'true'
) {
pageElements.push(<ProcessBreadcrumb hotCrumbs={hotCrumbs} />);
pageElements.push(
<h3>
Task: {basicTask.name_for_display} (
{basicTask.process_model_display_name}){statusString}
</h3>
);
pageElements.push({
key: 'process-breadcrumb',
component: <ProcessBreadcrumb hotCrumbs={hotCrumbs} />,
});
pageElements.push({
key: 'task-name',
component: (
<h3>
Task: {basicTask.name_for_display} (
{basicTask.process_model_display_name}){statusString}
</h3>
),
});
}
}
if (guestConfirmationText) {
pageElements.push(
<MarkdownRenderer linkTarget="_blank" source={guestConfirmationText} />
);
pageElements.push({
key: 'guest-confirmation-text',
component: (
<MarkdownRenderer linkTarget="_blank" source={guestConfirmationText} />
),
});
} else if (basicTask && taskData) {
pageElements.push(<InstructionsForEndUser task={taskWithTaskData} />);
pageElements.push(formElement());
pageElements.push({
key: 'instructions-for-end-user',
component: <InstructionsForEndUser task={taskWithTaskData} />,
});
pageElements.push({ key: 'main-form', component: formElement() });
} else if (!atLeastOneTaskFetchHasError) {
pageElements.push(getLoadingIcon());
pageElements.push({ key: 'loading-icon', component: getLoadingIcon() });
}
// typescript gets angry if we return an array of elements not in a tag
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{pageElements}</>;
return <>{renderElementsForArray(pageElements)}</>;
}