Skip to content

Commit

Permalink
[Fix] display-name: Accept forwardRef and Memo nesting in newer Rea…
Browse files Browse the repository at this point in the history
…ct versions
  • Loading branch information
TildaDares authored and ljharb committed Jul 5, 2022
1 parent 151a6ed commit 5769b53
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 4 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -10,12 +10,14 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange

### Fixed
* [`jsx-no-literals`]: properly error on children with noAttributeStrings: true ([#3317][] @TildaDares)
* [`jsx-key`]: catch key errors inside conditional statements ([#3320][] @TildaDates)
* [`jsx-key`]: catch key errors inside conditional statements ([#3320][] @TildaDares)
* [`display-name`]: Accept forwardRef and Memo nesting in newer React versions ([#3321][] @TildaDares)

### Changed
* [Refactor] [`jsx-indent-props`]: improved readability of the checkNodesIndent function ([#3315][] @caroline223)
* [Tests] [`jsx-indent`], [`jsx-one-expression-per-line`]: add passing test cases ([#3314][] @ROSSROSALES)

[#3321]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3321
[#3320]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3320
[#3317]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3317
[#3315]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3315
Expand Down
19 changes: 19 additions & 0 deletions lib/rules/display-name.js
Expand Up @@ -11,6 +11,7 @@ const Components = require('../util/Components');
const astUtil = require('../util/ast');
const componentUtil = require('../util/componentUtil');
const docsUrl = require('../util/docsUrl');
const testReactVersion = require('../util/version').testReactVersion;
const propsUtil = require('../util/props');
const report = require('../util/report');

Expand Down Expand Up @@ -58,11 +59,29 @@ module.exports = {
});
}

/**
* Checks if React.forwardRef is nested inside React.memo
* @param {ASTNode} node The AST node being checked.
* @returns {Boolean} True if React.forwardRef is nested inside React.memo, false if not.
*/
function isNestedMemo(node) {
const argumentIsCallExpression = node.arguments && node.arguments[0] && node.arguments[0].type === 'CallExpression';

return node.type === 'CallExpression' && argumentIsCallExpression && utils.isPragmaComponentWrapper(node);
}

/**
* Reports missing display name for a given component
* @param {Object} component The component to process
*/
function reportMissingDisplayName(component) {
if (
testReactVersion(context, '^0.14.10 || ^15.7.0 || >= 16.12.0')
&& isNestedMemo(component.node)
) {
return;
}

report(context, messages.noDisplayName, 'noDisplayName', {
node: component.node,
});
Expand Down
113 changes: 110 additions & 3 deletions tests/lib/rules/display-name.js
Expand Up @@ -601,6 +601,94 @@ ruleTester.run('display-name', rule, {
)
`,
},
{
// Nested React.forwardRef should be accepted in React versions in the following range:
// ^0.14.10 || ^15.7.0 || >= 16.12.0
code: `
import React from 'react'
const MemoizedForwardRefComponentLike = React.memo(
React.forwardRef(function({ world }, ref) {
return <div ref={ref}>Hello {world}</div>
})
)
`,
settings: {
react: {
version: '16.14.0',
},
},
},
{
// Nested React.forwardRef should be accepted in React versions in the following range:
// ^0.14.10 || ^15.7.0 || >= 16.12.0
code: `
import React from 'react'
const MemoizedForwardRefComponentLike = React.memo(
React.forwardRef(({ world }, ref) => {
return <div ref={ref}>Hello {world}</div>
})
)
`,
settings: {
react: {
version: '15.7.0',
},
},
},
{
// Nested React.forwardRef should be accepted in React versions in the following range:
// ^0.14.10 || ^15.7.0 || >= 16.12.0
code: `
import React from 'react'
const MemoizedForwardRefComponentLike = React.memo(
React.forwardRef(function ComponentLike({ world }, ref) {
return <div ref={ref}>Hello {world}</div>
})
)
`,
settings: {
react: {
version: '16.12.1',
},
},
},
{
// Nested React.forwardRef should be accepted in React versions in the following range:
// ^0.14.10 || ^15.7.0 || >= 16.12.0
code: `
export const ComponentWithForwardRef = React.memo(
React.forwardRef(function Component({ world }) {
return <div>Hello {world}</div>
})
)
`,
settings: {
react: {
version: '0.14.11',
},
},
},
{
// Nested React.forwardRef should be accepted in React versions in the following range:
// ^0.14.10 || ^15.7.0 || >= 16.12.0
code: `
import React from 'react'
const MemoizedForwardRefComponentLike = React.memo(
React.forwardRef(function({ world }, ref) {
return <div ref={ref}>Hello {world}</div>
})
)
`,
settings: {
react: {
version: '15.7.1',
},
},
},
]),

invalid: parsers.all([
Expand Down Expand Up @@ -823,7 +911,9 @@ ruleTester.run('display-name', rule, {
errors: [{ messageId: 'noDisplayName' }],
},
{
// Only trigger an error for the outer React.memo
// Only trigger an error for the outer React.memo,
// if the React version is not in the following range:
// ^0.14.10 || ^15.7.0 || >= 16.12.0
code: `
import React from 'react'
Expand All @@ -837,19 +927,31 @@ ruleTester.run('display-name', rule, {
{
messageId: 'noDisplayName',
}],
settings: {
react: {
version: '15.6.0',
},
},
},
{
// Only trigger an error for the outer React.memo
// Only trigger an error for the outer React.memo,
// if the React version is not in the following range:
// ^0.14.10 || ^15.7.0 || >= ^16.12.0
code: `
import React from 'react'
const MemoizedForwardRefComponentLike = React.memo(
React.forwardRef(function({ world }, ref) {
return <div ref={ref}>Hello {world}</div>
})
})
)
`,
errors: [{ messageId: 'noDisplayName' }],
settings: {
react: {
version: '0.14.2',
},
},
},
{
// React does not handle the result of forwardRef being passed into memo
Expand All @@ -865,6 +967,11 @@ ruleTester.run('display-name', rule, {
)
`,
errors: [{ messageId: 'noDisplayName' }],
settings: {
react: {
version: '15.0.1',
},
},
},
{
code: `
Expand Down

0 comments on commit 5769b53

Please sign in to comment.