Skip to content

Commit

Permalink
[DX] Add .displayNames to new sub-component utils
Browse files Browse the repository at this point in the history
- makes it easier to debug code in React Devtools' Components tab

+ update our lint rule that we set to `.forwardRef` to also apply to `.memo()`ed components - will matter more as we start to optimize performance across EUI
  • Loading branch information
cee-chen committed Jan 31, 2024
1 parent c81261e commit 6407f8d
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 23 deletions.
33 changes: 20 additions & 13 deletions scripts/eslint-plugin/forward_ref_display_name.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Enforce display name to forwardRef components',
description:
'Enforce display name on components wrapped in forwardRef & memo',
},
},
create: function(context) {
const forwardRefUsages = [];
create: function (context) {
const usagesToCheck = [];
const displayNameUsages = [];
return {
VariableDeclarator(node) {
Expand All @@ -16,14 +17,20 @@ module.exports = {
node.init.callee.type === 'MemberExpression'
) {
if (
node.init.callee.property &&
node.init.callee.property.name === 'forwardRef'
node.init.callee.property?.name === 'forwardRef' ||
node.init.callee.property?.name === 'memo'
) {
forwardRefUsages.push(node.id);
usagesToCheck.push({
id: node.id,
type: node.init.callee.property.name,
});
}
}
if (node.init.callee && node.init.callee.name === 'forwardRef') {
forwardRefUsages.push(node.id);
if (
node.init.callee?.name === 'forwardRef' ||
node.init.callee?.name === 'memo'
) {
usagesToCheck.push({ id: node.id, type: node.init.callee.name });
}
}
},
Expand All @@ -38,19 +45,19 @@ module.exports = {
}
},
'Program:exit'() {
forwardRefUsages.forEach(identifier => {
if (!isDisplayNameUsed(identifier)) {
usagesToCheck.forEach(({ id, type }) => {
if (!isDisplayNameUsed(id)) {
context.report({
node: identifier,
message: 'Forward ref components must use a display name',
node: id,
message: `Components wrapped in React.${type} must set a manual displayName`,
});
}
});
},
};
function isDisplayNameUsed(identifier) {
const node = displayNameUsages.find(
displayName => displayName.name === identifier.name
(displayName) => displayName.name === identifier.name
);
return !!node;
}
Expand Down
15 changes: 14 additions & 1 deletion scripts/eslint-plugin/forward_ref_display_name.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const ruleTester = new RuleTester({
const valid = [
`const Component = React.forwardRef<ref>(() => {})
Component.displayName = "EuiBadgeGroup"
`,
`const Component = React.memo(() => {})
Component.displayName = "EuiHighlight"
`,
];

Expand All @@ -16,7 +19,17 @@ const invalid = [
code: 'const Component = React.forwardRef<ref>(() => {})',
errors: [
{
message: 'Forward ref components must use a display name',
message:
'Components wrapped in React.forwardRef must set a manual displayName',
},
],
},
{
code: 'const Component = React.memo(() => {})',
errors: [
{
message:
'Components wrapped in React.memo must set a manual displayName',
},
],
},
Expand Down
1 change: 1 addition & 0 deletions src/components/highlight/_highlight_all.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const HighlightAll: FunctionComponent<_SharedSubcomponentProps> = memo(
);
}
);
HighlightAll.displayName = '_HighlightAll';

/**
* Chunk utility
Expand Down
1 change: 1 addition & 0 deletions src/components/highlight/_highlight_first.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ export const HighlightFirst: FunctionComponent<_SharedSubcomponentProps> = memo(
);
}
);
HighlightFirst.displayName = '_HighlightFirst';
20 changes: 11 additions & 9 deletions src/components/highlight/highlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React, {
HTMLAttributes,
FunctionComponent,
ElementType,
useCallback,
useMemo,
} from 'react';

import { CommonProps } from '../common';
Expand Down Expand Up @@ -57,15 +57,17 @@ export const EuiHighlight: FunctionComponent<EuiHighlightProps> = ({
}) => {
const hasSearch = search && search.length > 0;

const HighlightComponent: FunctionComponent<{ children: string }> =
useCallback(
({ children }) => (
<EuiMark hasScreenReaderHelpText={hasScreenReaderHelpText}>
{children}
</EuiMark>
),
[hasScreenReaderHelpText]
const HighlightComponent = useMemo(() => {
const Component: FunctionComponent<{ children: string }> = ({
children,
}) => (
<EuiMark hasScreenReaderHelpText={hasScreenReaderHelpText}>
{children}
</EuiMark>
);
Component.displayName = '_HighlightComponent';
return Component;
}, [hasScreenReaderHelpText]);

return (
<span className={className} {...rest}>
Expand Down

0 comments on commit 6407f8d

Please sign in to comment.