Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[perf feedback] Remove React.memo for subcomponents that do not rea…
Browse files Browse the repository at this point in the history
…lly need it
cee-chen committed Feb 5, 2024
1 parent 64ab4d8 commit 7ed5ce3
Showing 2 changed files with 72 additions and 80 deletions.
71 changes: 34 additions & 37 deletions src/components/highlight/_highlight_all.tsx
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import React, { memo, useMemo, FunctionComponent } from 'react';
import React, { useMemo, FunctionComponent } from 'react';
import escapeRegExp from 'lodash/escapeRegExp';

import type { _SharedSubcomponentProps } from './highlight';
@@ -17,46 +17,43 @@ import type { _SharedSubcomponentProps } from './highlight';
*
* Uses regex rather than indexOf/while loops for easier dev maintainability
*/
export const HighlightAll: FunctionComponent<_SharedSubcomponentProps> = memo(
({
searchSubject,
searchValue: _searchValue,
isStrict,
highlightComponent: HighlightComponent = 'mark',
}) => {
const searchValue = useMemo(() => {
return Array.isArray(_searchValue)
? _searchValue.map(escapeRegExp).join('|')
: escapeRegExp(_searchValue);
}, [_searchValue]);
export const HighlightAll: FunctionComponent<_SharedSubcomponentProps> = ({
searchSubject,
searchValue: _searchValue,
isStrict,
highlightComponent: HighlightComponent = 'mark',
}) => {
const searchValue = useMemo(() => {
return Array.isArray(_searchValue)
? _searchValue.map(escapeRegExp).join('|')
: escapeRegExp(_searchValue);
}, [_searchValue]);

const chunks = useMemo(() => {
const regex = new RegExp(searchValue, isStrict ? 'g' : 'gi');
const matches = [...searchSubject.matchAll(regex)].map((match) => ({
start: match.index || 0,
end: (match.index || 0) + match[0].length,
}));
const chunks = useMemo(() => {
const regex = new RegExp(searchValue, isStrict ? 'g' : 'gi');
const matches = [...searchSubject.matchAll(regex)].map((match) => ({
start: match.index || 0,
end: (match.index || 0) + match[0].length,
}));

return fillInChunks(matches, searchSubject.length);
}, [searchValue, searchSubject, isStrict]);
return fillInChunks(matches, searchSubject.length);
}, [searchValue, searchSubject, isStrict]);

return (
<>
{chunks.map((chunk) => {
const { end, highlight, start } = chunk;
const value = searchSubject.substring(start, end);
return (
<>
{chunks.map((chunk) => {
const { end, highlight, start } = chunk;
const value = searchSubject.substring(start, end);

return highlight ? (
<HighlightComponent key={start}>{value}</HighlightComponent>
) : (
value
);
})}
</>
);
}
);
HighlightAll.displayName = '_HighlightAll';
return highlight ? (
<HighlightComponent key={start}>{value}</HighlightComponent>
) : (
value
);
})}
</>
);
};

/**
* Chunk utility
81 changes: 38 additions & 43 deletions src/components/highlight/_highlight_first.tsx
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import React, { memo, FunctionComponent } from 'react';
import React, { FunctionComponent } from 'react';

import { _SharedSubcomponentProps } from './highlight';

@@ -16,49 +16,44 @@ import { _SharedSubcomponentProps } from './highlight';
*
* Uses indexOf for performance (which does matter for, e.g. EuiSelectable searching)
*/
export const HighlightFirst: FunctionComponent<_SharedSubcomponentProps> = memo(
({
searchSubject,
searchValue,
isStrict,
highlightComponent: HighlightComponent = 'mark',
}) => {
if (Array.isArray(searchValue)) {
throw new Error(
'Cannot parse multiple search strings without `highlightAll` enabled'
);
}
export const HighlightFirst: FunctionComponent<_SharedSubcomponentProps> = ({
searchSubject,
searchValue,
isStrict,
highlightComponent: HighlightComponent = 'mark',
}) => {
if (Array.isArray(searchValue)) {
throw new Error(
'Cannot parse multiple search strings without `highlightAll` enabled'
);
}

const normalizedSearchSubject = isStrict
? searchSubject
: searchSubject.toLowerCase();
const normalizedSearchValue = isStrict
? searchValue
: searchValue.toLowerCase();
const normalizedSearchSubject = isStrict
? searchSubject
: searchSubject.toLowerCase();
const normalizedSearchValue = isStrict
? searchValue
: searchValue.toLowerCase();

const indexOfMatch = normalizedSearchSubject.indexOf(normalizedSearchValue);
if (indexOfMatch === -1) {
return <>{searchSubject}</>;
}
const indexOfMatch = normalizedSearchSubject.indexOf(normalizedSearchValue);
if (indexOfMatch === -1) {
return <>{searchSubject}</>;
}

const preMatch = searchSubject.substring(0, indexOfMatch);
const match = searchSubject.substring(
indexOfMatch,
indexOfMatch + searchValue.length
);
const postMatch = searchSubject.substring(
indexOfMatch + searchValue.length
);
const preMatch = searchSubject.substring(0, indexOfMatch);
const match = searchSubject.substring(
indexOfMatch,
indexOfMatch + searchValue.length
);
const postMatch = searchSubject.substring(indexOfMatch + searchValue.length);

return (
// Note: React 16/17 will render empty strings in the DOM. The
// `|| undefined` prevents this & keeps snapshots the same for all versions
<>
{preMatch || undefined}
<HighlightComponent>{match}</HighlightComponent>
{postMatch || undefined}
</>
);
}
);
HighlightFirst.displayName = '_HighlightFirst';
return (
// Note: React 16/17 will render empty strings in the DOM. The
// `|| undefined` prevents this & keeps snapshots the same for all versions
<>
{preMatch || undefined}
<HighlightComponent>{match}</HighlightComponent>
{postMatch || undefined}
</>
);
};

0 comments on commit 7ed5ce3

Please sign in to comment.