Skip to content

Commit f9b96d3

Browse files
committed
Add detection of subRender methods to prefer-stateless-function
1 parent 27b8279 commit f9b96d3

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

docs/rules/prefer-stateless-function.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This rule will check your class based React components for
1111
* extension of `React.PureComponent` (if the `ignorePureComponents` flag is true)
1212
* presence of `ref` attribute in JSX
1313
* the use of decorators
14+
* methods inside a React Component that return JSX other than the `render()` method (if the `subRenderMethods` flag is true)
1415
* `render` method that return anything but JSX: `undefined`, `null`, etc. (only in React <15.0.0, see [shared settings](https://github.com/yannickcr/eslint-plugin-react/blob/master/README.md#configuration) for React version configuration)
1516

1617
If none of these elements are found, the rule will warn you to write this component as a pure function.
@@ -55,12 +56,13 @@ class Foo extends React.Component {
5556

5657
```js
5758
...
58-
"react/prefer-stateless-function": [<enabled>, { "ignorePureComponents": <ignorePureComponents> }]
59+
"react/prefer-stateless-function": [<enabled>, { "ignorePureComponents": <ignorePureComponents>, "subRenderMethods": <subRenderMethods> }]
5960
...
6061
```
6162

6263
* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
6364
* `ignorePureComponents`: optional boolean set to `true` to ignore components extending from `React.PureComponent` (default to `false`).
65+
* `subRenderMethods`: optional boolean set to `true` to also warn on methods in React Components that return JSX other than the `render()` method (default to `false`).
6466

6567
### `ignorePureComponents`
6668

@@ -85,3 +87,27 @@ class Foo extends React.PureComponent {
8587
}
8688
}
8789
```
90+
91+
### `subRenderMethods`
92+
93+
When `true` the rule will warn when you use methods that return JSX in a React Component other than the `render()` method
94+
95+
The following patterns is considered a warning:
96+
97+
```jsx
98+
class Foo extends React.Component {
99+
constructor(props) {
100+
super(props);
101+
102+
this.state = {myState: ""}
103+
}
104+
105+
renderFoo() {
106+
return <span>{this.state.myState}</span>
107+
}
108+
109+
render() {
110+
return <div>{this.renderFoo()}</div>;
111+
}
112+
}
113+
```

lib/rules/prefer-stateless-function.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ module.exports = {
2828
ignorePureComponents: {
2929
default: false,
3030
type: 'boolean'
31+
},
32+
// Enable by default when making a new major release.
33+
subRenderMethods: {
34+
default: false,
35+
type: 'boolean'
3136
}
3237
},
3338
additionalProperties: false
@@ -296,6 +301,20 @@ module.exports = {
296301
markThisAsUsed(node);
297302
},
298303

304+
// Report non-"render" methods that return JSX
305+
MethodDefinition: function(node) {
306+
if (
307+
utils.isES6Component(node.parent.parent) &&
308+
node.key.name !== 'render' &&
309+
utils.isReturningJSX(node.value)
310+
) {
311+
context.report({
312+
node: node,
313+
message: 'Method returning JSX should be written as stateless function component'
314+
});
315+
}
316+
},
317+
299318
// Mark `this` usage
300319
MemberExpression: function(node) {
301320
if (node.object.type !== 'ThisExpression') {

tests/lib/rules/prefer-stateless-function.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,33 @@ ruleTester.run('prefer-stateless-function', rule, {
305305
}
306306
`,
307307
parser: 'babel-eslint'
308+
}, {
309+
// Methods that do not return JSX are still valid
310+
code: `
311+
class Foo extends React.Component {
312+
renderString() {
313+
return "X";
314+
}
315+
316+
renderNumber() {
317+
return 42;
318+
}
319+
320+
getSomeData() {
321+
return {}
322+
}
323+
324+
render() {
325+
return (
326+
<div>
327+
{this.renderString()}
328+
{this.renderNumber()}
329+
{this.getSomeData()}
330+
</div>
331+
)
332+
}
333+
}
334+
`
308335
}
309336
],
310337

@@ -595,6 +622,22 @@ ruleTester.run('prefer-stateless-function', rule, {
595622
errors: [{
596623
message: 'Component should be written as a pure function'
597624
}]
625+
}, {
626+
// Sub-render method that returns JSX
627+
code: `
628+
class Foo extends React.Component {
629+
renderFoo() {
630+
return <div />;
631+
}
632+
633+
render() {
634+
return this.renderFoo();
635+
}
636+
}
637+
`,
638+
errors: [{
639+
message: 'Method returning JSX should be written as stateless function component'
640+
}]
598641
}
599642
]
600643
});

0 commit comments

Comments
 (0)