From c48cb1fade9088d6f9cfbf2d1620542390b03429 Mon Sep 17 00:00:00 2001
From: Henry Dineen <hdineen@hubspot.com>
Date: Tue, 27 Aug 2024 13:23:48 -0400
Subject: [PATCH] [New] `no-string-refs`: allow this.refs in > 18.3.0

---
 CHANGELOG.md                      |  5 +++++
 lib/rules/no-string-refs.js       |  4 +++-
 tests/lib/rules/no-string-refs.js | 36 +++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4387a1bae..18503c4c02 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
 
 ## Unreleased
 
+### Added
+* [`no-string-refs`]: allow this.refs in > 18.3.0 ([#3807][] @henryqdineen)
+
+[#3807]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3807
+
 ## [7.35.1] - 2024.09.02
 
 ### Fixed
diff --git a/lib/rules/no-string-refs.js b/lib/rules/no-string-refs.js
index bef6440441..145ad25780 100644
--- a/lib/rules/no-string-refs.js
+++ b/lib/rules/no-string-refs.js
@@ -8,6 +8,7 @@
 const componentUtil = require('../util/componentUtil');
 const docsUrl = require('../util/docsUrl');
 const report = require('../util/report');
+const testReactVersion = require('../util/version').testReactVersion;
 
 // ------------------------------------------------------------------------------
 // Rule Definition
@@ -42,6 +43,7 @@ module.exports = {
   },
 
   create(context) {
+    const checkRefsUsage = testReactVersion(context, '< 18.3.0'); // `this.refs` is writable in React 18.3.0 and later, see https://github.com/facebook/react/pull/28867
     const detectTemplateLiterals = context.options[0] ? context.options[0].noTemplateLiterals : false;
     /**
      * Checks if we are using refs
@@ -93,7 +95,7 @@ module.exports = {
 
     return {
       MemberExpression(node) {
-        if (isRefsUsage(node)) {
+        if (checkRefsUsage && isRefsUsage(node)) {
           report(context, messages.thisRefsDeprecated, 'thisRefsDeprecated', {
             node,
           });
diff --git a/tests/lib/rules/no-string-refs.js b/tests/lib/rules/no-string-refs.js
index 05f8bfe407..e52680b446 100644
--- a/tests/lib/rules/no-string-refs.js
+++ b/tests/lib/rules/no-string-refs.js
@@ -59,6 +59,19 @@ ruleTester.run('no-refs', rule, {
         });
       `,
     },
+    {
+      code: `
+        var Hello = createReactClass({
+          componentDidMount: function() {
+            var component = this.refs.hello;
+          },
+          render: function() {
+            return <div>Hello {this.props.name}</div>;
+          }
+        });
+      `,
+      settings: { react: { version: '18.3.0' } },
+    },
   ]),
 
   invalid: parsers.all([
@@ -73,6 +86,7 @@ ruleTester.run('no-refs', rule, {
           }
         });
       `,
+      settings: { react: { version: '18.2.0' } },
       errors: [{ messageId: 'thisRefsDeprecated' }],
     },
     {
@@ -83,6 +97,7 @@ ruleTester.run('no-refs', rule, {
           }
         });
       `,
+      settings: { react: { version: '18.2.0' } },
       errors: [{ messageId: 'stringInRefDeprecated' }],
     },
     {
@@ -93,6 +108,7 @@ ruleTester.run('no-refs', rule, {
           }
         });
       `,
+      settings: { react: { version: '18.2.0' } },
       errors: [{ messageId: 'stringInRefDeprecated' }],
     },
     {
@@ -106,6 +122,7 @@ ruleTester.run('no-refs', rule, {
           }
         });
       `,
+      settings: { react: { version: '18.2.0' } },
       errors: [
         { messageId: 'thisRefsDeprecated' },
         { messageId: 'stringInRefDeprecated' },
@@ -123,6 +140,7 @@ ruleTester.run('no-refs', rule, {
         });
       `,
       options: [{ noTemplateLiterals: true }],
+      settings: { react: { version: '18.2.0' } },
       errors: [
         { messageId: 'thisRefsDeprecated' },
         { messageId: 'stringInRefDeprecated' },
@@ -140,10 +158,28 @@ ruleTester.run('no-refs', rule, {
         });
       `,
       options: [{ noTemplateLiterals: true }],
+      settings: { react: { version: '18.2.0' } },
       errors: [
         { messageId: 'thisRefsDeprecated' },
         { messageId: 'stringInRefDeprecated' },
       ],
     },
+    {
+      code: `
+        var Hello = createReactClass({
+          componentDidMount: function() {
+          var component = this.refs.hello;
+          },
+          render: function() {
+            return <div ref={\`hello\${index}\`}>Hello {this.props.name}</div>;
+          }
+        });
+      `,
+      options: [{ noTemplateLiterals: true }],
+      settings: { react: { version: '18.3.0' } },
+      errors: [
+        { messageId: 'stringInRefDeprecated' },
+      ],
+    },
   ]),
 });