diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ff82d962e..51a60eaa52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * [`hook-use-state`]: add `allowDestructuredState` option ([#3449][] @ljharb) * add [`sort-default-props`] and deprecate [`jsx-sort-default-props`] ([#1861][] @alexzherdev) +### Changed +* [Perf] component detection: improve performance by avoiding traversing parents unnecessarily ([#3459][] @golopot) + +[#3459]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3459 [#3449]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3449 [#3424]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3429 [#1861]: https://github.com/jsx-eslint/eslint-plugin-react/pull/1861 diff --git a/lib/util/Components.js b/lib/util/Components.js index b112923f63..53acf1b4d6 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -109,7 +109,7 @@ class Components { set(node, props) { const list = Lists.get(this); let component = list[getId(node)]; - while (!component) { + while (!component || component.confidence < 1) { node = node.parent; if (!node) { return; @@ -477,7 +477,6 @@ function componentRule(rule, context) { } if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { - const isMethod = parent.type === 'Property' && parent.method; const isPropertyAssignment = parent.type === 'AssignmentExpression' && parent.left.type === 'MemberExpression'; const isModuleExportsAssignment = isPropertyAssignment @@ -562,6 +561,18 @@ function componentRule(rule, context) { return undefined; } + if ( + node.parent.type === 'Property' && ( + (node.parent.method && !node.parent.computed) // case: { f() { return ... } } + || (!node.id && !node.parent.computed) // case: { f: () => ... } + ) + ) { + if (isFirstLetterCapitalized(node.parent.key.name) && utils.isReturningJSX(node)) { + return node; + } + return undefined; + } + // Case like `React.memo(() => <>)` or `React.forwardRef(...)` const pragmaComponentWrapper = utils.getPragmaComponentWrapper(node); if (pragmaComponentWrapper && utils.isReturningJSXOrNull(node)) { @@ -576,10 +587,6 @@ function componentRule(rule, context) { return undefined; } - if (isMethod && !isFirstLetterCapitalized(node.parent.key.name)) { - return utils.isReturningJSX(node) ? node : undefined; - } - if (node.id) { return isFirstLetterCapitalized(node.id.name) ? node : undefined; } @@ -853,13 +860,8 @@ function componentRule(rule, context) { return; } - const component = utils.getParentComponent(); - if ( - !component - || (component.parent && component.parent.type === 'JSXExpressionContainer') - ) { - // Ban the node if we cannot find a parent component - components.add(node, 0); + const component = utils.getStatelessComponent(node); + if (!component) { return; } components.add(component, 2); @@ -871,7 +873,7 @@ function componentRule(rule, context) { return; } - node = utils.getParentComponent(); + node = utils.getStatelessComponent(node); if (!node) { return; } @@ -884,13 +886,8 @@ function componentRule(rule, context) { return; } - const component = utils.getParentComponent(); - if ( - !component - || (component.parent && component.parent.type === 'JSXExpressionContainer') - ) { - // Ban the node if we cannot find a parent component - components.add(node, 0); + const component = utils.getStatelessComponent(node); + if (!component) { return; } components.add(component, 2); diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index 4af2341169..738a9800ec 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -459,7 +459,7 @@ ruleTester.run('destructuring-assignment', rule, { }, { code: ` - var Hello = React.createClass({ + var Hello = createReactClass({ render: function() { return {this.props.foo}; }