Skip to content

Commit 3f227c8

Browse files
fix replace-string-ref to delete refs on unmount
Match string-ref semantics by deleting this.refs properties when callback refs receive null, instead of assigning null. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent b8e2edc commit 3f227c8

12 files changed

Lines changed: 93 additions & 12 deletions

File tree

‎codemods/replace-string-ref/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Replace string refs in React class components with callback refs that assign through `this.refs`.
44

5+
On unmount, React invokes callback refs with `null`. The generated callback deletes the `this.refs` property in that case (instead of assigning `null`) so behavior stays closer to string refs for checks like `typeof this.refs.refName`, `'refName' in this.refs`, and `Object.keys(this.refs)`.
6+
57
## Usage
68

79
```bash

‎codemods/replace-string-ref/scripts/codemod.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ function callbackRefText(refName: string): string {
5353
? `this.refs.${refName}`
5454
: `this.refs[${JSON.stringify(refName)}]`;
5555
return `ref={(ref) => {
56-
${assignmentTarget} = ref;
56+
if (ref === null) {
57+
delete ${assignmentTarget};
58+
} else {
59+
${assignmentTarget} = ref;
60+
}
5761
}}`;
5862
}
5963

‎codemods/replace-string-ref/tests/class-component-custom-import-names/expected.tsx‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@ import React1, { PureComponent as PureComponent1 } from "react";
33
class C extends React1.Component {
44
render() {
55
return (<div ref={(ref) => {
6-
this.refs.refName = ref;
6+
if (ref === null) {
7+
delete this.refs.refName;
8+
} else {
9+
this.refs.refName = ref;
10+
}
711
}} />);
812
}
913
}
1014

1115
class C1 extends PureComponent1 {
1216
render() {
1317
return (<div ref={(ref) => {
14-
this.refs.refName = ref;
18+
if (ref === null) {
19+
delete this.refs.refName;
20+
} else {
21+
this.refs.refName = ref;
22+
}
1523
}} />);
1624
}
1725
}

‎codemods/replace-string-ref/tests/class-component-default-import/expected.tsx‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@ import React from "react";
33
class C extends React.Component {
44
render() {
55
return (<div ref={(ref) => {
6-
this.refs.refName = ref;
6+
if (ref === null) {
7+
delete this.refs.refName;
8+
} else {
9+
this.refs.refName = ref;
10+
}
711
}} />);
812
}
913
}
1014

1115
class C1 extends React.PureComponent {
1216
render() {
1317
return (<div ref={(ref) => {
14-
this.refs.refName = ref;
18+
if (ref === null) {
19+
delete this.refs.refName;
20+
} else {
21+
this.refs.refName = ref;
22+
}
1523
}} />);
1624
}
1725
}

‎codemods/replace-string-ref/tests/class-component-named-import/expected.tsx‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@ import { Component, PureComponent } from "react";
33
class C extends Component {
44
render() {
55
return (<div ref={(ref) => {
6-
this.refs.refName = ref;
6+
if (ref === null) {
7+
delete this.refs.refName;
8+
} else {
9+
this.refs.refName = ref;
10+
}
711
}} />);
812
}
913
}
1014

1115
class C1 extends PureComponent {
1216
render() {
1317
return (<div ref={(ref) => {
14-
this.refs.refName = ref;
18+
if (ref === null) {
19+
delete this.refs.refName;
20+
} else {
21+
this.refs.refName = ref;
22+
}
1523
}} />);
1624
}
1725
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from "react";
2+
3+
class C extends React.Component {
4+
render() {
5+
return (<div ref={(ref) => {
6+
if (ref === null) {
7+
delete this.refs.refName;
8+
} else {
9+
this.refs.refName = ref;
10+
}
11+
}} />);
12+
}
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react";
2+
3+
class C extends React.Component {
4+
render() {
5+
return <div ref="refName" />;
6+
}
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"string-ref-replacements": [
3+
{
4+
"cardinality": {
5+
"file": "tests/delete-ref-on-unmount/input.tsx",
6+
"refs": "refName"
7+
},
8+
"count": 1
9+
}
10+
]
11+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import React from "react";
22
export default class C extends React.Component { render() { return (<div ref={(ref) => {
3-
this.refs.refName = ref;
3+
if (ref === null) {
4+
delete this.refs.refName;
5+
} else {
6+
this.refs.refName = ref;
7+
}
48
}} />); } }
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import React from "react";
22
class C extends React.Component { render() { return <><div ref={(ref) => {
3-
this.refs.a = ref;
3+
if (ref === null) {
4+
delete this.refs.a;
5+
} else {
6+
this.refs.a = ref;
7+
}
48
}} /><span ref={(ref) => {
5-
this.refs.b = ref;
9+
if (ref === null) {
10+
delete this.refs.b;
11+
} else {
12+
this.refs.b = ref;
13+
}
614
}} /></>; } }

0 commit comments

Comments
 (0)