Skip to content

Commit 2959438

Browse files
committed
fix: react component key generation and usage
HCRC-178. Important updates related to React component key generation and it's usage: 1. React keys must be passed directly to JSX without using spread. 2. Remove all Math.random() usages as react component key, because they are considered as bad practise. Rules of keys: - Keys must be unique among siblings. However, it’s okay to use the same keys for JSX nodes in different arrays. - Keys must not change or that defeats their purpose! Don’t generate them while rendering. > Do not generate keys on the fly, e.g. with key={Math.random()}. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data. Ref. https://18.react.dev/learn/rendering-lists#rules-of-keys
1 parent 0651b69 commit 2959438

4 files changed

Lines changed: 21 additions & 12 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
"eslint-plugin-react-hooks": "^5.0.0",
109109
"git-rev-sync": "^3.0.2",
110110
"graphql": "^16.9.0",
111-
"hds-react": "^4.8.0",
111+
"hds-react": "4.8.0",
112112
"identity-obj-proxy": "^3.0.0",
113113
"jest": "^29.7.0",
114114
"jest-axe": "^9.0.0",
@@ -151,4 +151,4 @@
151151
"msw": {
152152
"workerDirectory": "public"
153153
}
154-
}
154+
}

src/core/archiveSearchPageContent/ArchiveSearchPageContent.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,24 +186,29 @@ export interface SearchPageContentProps {
186186
*/
187187
createLargeCard?: (
188188
item: CollectionItemType,
189+
index?: number,
189190
) => React.ReactElement<typeof LargeCard>;
190-
createCard?: (item: CollectionItemType) => React.ReactElement<typeof Card>;
191+
createCard?: (
192+
item: CollectionItemType,
193+
index?: number,
194+
) => React.ReactElement<typeof Card>;
191195
}
192196

193-
export const defaultLargeCard = (item: CollectionItemType) => (
197+
export const defaultLargeCard = (item: CollectionItemType, index?: number) => (
194198
<LargeCard
195199
{...item}
200+
key={item?.id ?? `card-${index}`}
196201
title={
197202
(isEventType(item)
198203
? item.name[DEFAULT_LOCALE]
199204
: (item as ArticleType | PageType)?.title) || undefined
200205
}
201206
/>
202207
);
203-
export const defaultCreateCard = (item: CollectionItemType) => (
208+
export const defaultCreateCard = (item: CollectionItemType, index?: number) => (
204209
<Card
205210
{...item}
206-
key={item?.id}
211+
key={item?.id ?? `card-${index}`}
207212
title={
208213
(isEventType(item)
209214
? item.name[DEFAULT_LOCALE]
@@ -231,7 +236,7 @@ export function ArchiveCollection({
231236
{largeFirstItem && createLargeCard(firstItem)}
232237
</div>
233238
<Grid className={styles.grid}>
234-
{gridItems.map((item) => createCard(item))}
239+
{gridItems.map((item, index) => createCard(item, index))}
235240
</Grid>
236241
</>
237242
);

src/core/carousel/utils/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function splitArrayIntoChunksOfLen(
2323
* @return an unique key based on input data.
2424
*/
2525
export const getItemSetKey = (index: number, itemSetId?: string) =>
26-
`itemSet-${itemSetId ?? Math.random()}-${index}`;
26+
`itemSet-${itemSetId ?? ''}-${index}`;
2727

2828
/**
2929
* Create an unique key for item set.
@@ -36,7 +36,7 @@ export const getItemSetItemKey = (
3636
index: number,
3737
itemId?: string,
3838
itemSetPrefix = 'itemSet-item',
39-
) => `${itemSetPrefix}-${itemId ?? Math.random()}-${index}`;
39+
) => `${itemSetPrefix}-${itemId ?? ''}-${index}`;
4040

4141
/**
4242
* @param item - item (element of the array).
@@ -45,6 +45,6 @@ export const getItemSetItemKey = (
4545
*/
4646
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4747
export const getSlideDotKey = (item: any, index: number) =>
48-
`slide-dot-${item?.id ?? Math.random()}-${index}`;
48+
`slide-dot-${item?.id ?? ''}-${index}`;
4949

50-
export const getLoadMoreKey = () => `carousel-loadmore-${Math.random()}`;
50+
export const getLoadMoreKey = () => 'carousel-loadmore';

src/core/pageContent/PageContent.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ export const defaultCollections = ({
194194
}) =>
195195
getCollections(page?.modules ?? [], true)?.reduce(
196196
(collectionElements: React.JSX.Element[], collection) => {
197+
const key = `collection-${btoa(`${collection?.id ?? ''}-${collection?.title ?? ''}-${collection?.description ?? ''}`)}`;
197198
const commonCollectionProps = {
198-
key: `collection-${Math.random()}`,
199199
title: collection.title,
200200
description: collection.description,
201201
type: getCollectionUIType(collection),
@@ -207,6 +207,7 @@ export const defaultCollections = ({
207207
collectionElements.push(
208208
<EventSearchCollection
209209
{...commonCollectionProps}
210+
key={key}
210211
collection={collection}
211212
/>,
212213
);
@@ -216,6 +217,7 @@ export const defaultCollections = ({
216217
collectionElements.push(
217218
<EventSelectionCollection
218219
{...commonCollectionProps}
220+
key={key}
219221
collection={collection}
220222
/>,
221223
);
@@ -225,6 +227,7 @@ export const defaultCollections = ({
225227
collectionElements.push(
226228
<LocationsSelectionCollection
227229
{...commonCollectionProps}
230+
key={key}
228231
collection={collection}
229232
locale={page?.language?.locale as LanguageCodeEnum}
230233
/>,
@@ -234,6 +237,7 @@ export const defaultCollections = ({
234237
collectionElements.push(
235238
<PageArticleCollection
236239
{...commonCollectionProps}
240+
key={key}
237241
collection={collection}
238242
/>,
239243
);

0 commit comments

Comments
 (0)