diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b8a610a50..ecb9789788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/lib/rules/display-name.js b/lib/rules/display-name.js index a99aabceee..c07f9255b4 100644 --- a/lib/rules/display-name.js +++ b/lib/rules/display-name.js @@ -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'); @@ -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, }); diff --git a/tests/lib/rules/display-name.js b/tests/lib/rules/display-name.js index 85e076d4d1..445add83a5 100644 --- a/tests/lib/rules/display-name.js +++ b/tests/lib/rules/display-name.js @@ -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