Skip to content

Commit 33b6cde

Browse files
committed
feat: Add codemod to transform string refs to arrow-functions
1 parent 243edf6 commit 33b6cde

12 files changed

+299
-0
lines changed

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,76 @@ guide](https://github.com/airbnb/javascript/blob/7684892951ef663e1c4e62ad57d662e
143143
npx react-codemod sort-comp <path>
144144
```
145145

146+
#### `string-refs`
147+
148+
WARNING: Only apply this codemod if you've fixed all warnings like this:
149+
150+
```
151+
152+
```
153+
154+
This codemod will convert deprecated string refs to callback refs.
155+
156+
Input:
157+
158+
```jsx
159+
import * as React from "react";
160+
161+
class ParentComponent extends React.Component {
162+
render() {
163+
return <div ref="refComponent" />;
164+
}
165+
}
166+
```
167+
168+
Output:
169+
170+
```jsx
171+
import * as React from "react";
172+
173+
class ParentComponent extends React.Component {
174+
render() {
175+
return (
176+
<div
177+
ref={(current) => {
178+
this.refs["refComponent"] = current;
179+
}}
180+
/>
181+
);
182+
}
183+
}
184+
```
185+
186+
Note that this only works for string literals.
187+
Referring to the ref with a variable will not trigger the transform:
188+
Input:
189+
190+
```jsx
191+
import * as React from "react";
192+
193+
const refName = "refComponent";
194+
195+
class ParentComponent extends React.Component {
196+
render() {
197+
return <div ref={refName} />;
198+
}
199+
}
200+
```
201+
202+
Output (nothing changed):
203+
204+
```jsx
205+
import * as React from "react";
206+
207+
const refName = "refComponent";
208+
209+
class ParentComponent extends React.Component {
210+
render() {
211+
return <div ref={refName} />;
212+
}
213+
}
214+
```
215+
146216
#### `update-react-imports`
147217

148218
[As of Babel 7.9.0](https://babeljs.io/blog/2020/03/16/7.9.0#a-new-jsx-transform-11154-https-githubcom-babel-babel-pull-11154), when using `runtime: automatic` in `@babel/preset-react` or `@babel/plugin-transform-react-jsx`, you will not need to explicitly import React for compiling jsx. This codemod removes the redundant import statements. It also converts default imports (`import React from 'react'`) to named imports (e.g. `import { useState } from 'react'`).

bin/cli.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ const TRANSFORMER_INQUIRER_CHOICES = [
188188
'Reorders React component methods to match the ESLint react/sort-comp rule.',
189189
value: 'sort-comp'
190190
},
191+
{
192+
name:
193+
'string-refs: Converts deprecated string refs to callback refs.',
194+
value: 'string-refs'
195+
},
191196
{
192197
name: 'update-react-imports: Removes redundant import statements from explicitly importing React to compile JSX and converts default imports to destructured named imports',
193198
value: 'update-react-imports',
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as React from "react";
2+
3+
class ParentComponent extends React.Component {
4+
render() {
5+
return (
6+
<div ref="P" id="P">
7+
<div ref="P_P1" id="P_P1">
8+
<span ref="P_P1_C1" id="P_P1_C1" />
9+
<span ref="P_P1_C2" id="P_P1_C2" />
10+
</div>
11+
<div ref="P_OneOff" id="P_OneOff" />
12+
</div>
13+
);
14+
}
15+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from "react";
2+
3+
class ParentComponent extends React.Component {
4+
render() {
5+
return (
6+
<div ref={current => {
7+
this.refs['P'] = current;
8+
}} id="P">
9+
<div ref={current => {
10+
this.refs['P_P1'] = current;
11+
}} id="P_P1">
12+
<span ref={current => {
13+
this.refs['P_P1_C1'] = current;
14+
}} id="P_P1_C1" />
15+
<span ref={current => {
16+
this.refs['P_P1_C2'] = current;
17+
}} id="P_P1_C2" />
18+
</div>
19+
<div ref={current => {
20+
this.refs['P_OneOff'] = current;
21+
}} id="P_OneOff" />
22+
</div>
23+
);
24+
}
25+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as React from "react";
2+
3+
<div ref="bad" />;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as React from "react";
2+
3+
<div ref={current => {
4+
this.refs['bad'] = current;
5+
}} />;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as React from "react";
2+
3+
class ParentComponent extends React.Component {
4+
// Actual code probably has more accurated types.
5+
// Codemod might cause TypeScript errors but these are good errors since they reveal unsound code.
6+
refs: Record<string, any>;
7+
8+
render() {
9+
return (
10+
<div ref="P" id="P">
11+
<div ref="P_P1" id="P_P1">
12+
<span ref="P_P1_C1" id="P_P1_C1" />
13+
<span ref="P_P1_C2" id="P_P1_C2" />
14+
</div>
15+
<div ref="P_OneOff" id="P_OneOff" />
16+
</div>
17+
);
18+
}
19+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from "react";
2+
3+
class ParentComponent extends React.Component {
4+
// Actual code probably has more accurated types.
5+
// Codemod might cause TypeScript errors but these are good errors since they reveal unsound code.
6+
refs: Record<string, any>;
7+
8+
render() {
9+
return (
10+
<div ref={current => {
11+
this.refs['P'] = current;
12+
}} id="P">
13+
<div ref={current => {
14+
this.refs['P_P1'] = current;
15+
}} id="P_P1">
16+
<span ref={current => {
17+
this.refs['P_P1_C1'] = current;
18+
}} id="P_P1_C1" />
19+
<span ref={current => {
20+
this.refs['P_P1_C2'] = current;
21+
}} id="P_P1_C2" />
22+
</div>
23+
<div ref={current => {
24+
this.refs['P_OneOff'] = current;
25+
}} id="P_OneOff" />
26+
</div>
27+
);
28+
}
29+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as React from "react";
2+
3+
class ParentComponent extends React.Component {
4+
render() {
5+
const refName = "P";
6+
// Giving up. Would need to implement scope tracking.
7+
return <div ref={refName} id="P"></div>;
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as React from "react";
2+
3+
class ParentComponent extends React.Component {
4+
render() {
5+
const refName = "P";
6+
// Giving up. Would need to implement scope tracking.
7+
return <div ref={refName} id="P"></div>;
8+
}
9+
}

0 commit comments

Comments
 (0)