Skip to content

Commit dc895db

Browse files
committed
Merge pull request #197 from markdalgleish/no-set-state
Add no-set-state rule
2 parents b2bfc08 + 1a3ac1e commit dc895db

File tree

5 files changed

+193
-0
lines changed

5 files changed

+193
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Finally, enable all of the rules that you would like to use.
5555
"react/jsx-uses-react": 1,
5656
"react/jsx-uses-vars": 1,
5757
"react/no-danger": 1,
58+
"react/no-set-state": 1,
5859
"react/no-did-mount-set-state": 1,
5960
"react/no-did-update-set-state": 1,
6061
"react/no-multi-comp": 1,
@@ -85,6 +86,7 @@ Finally, enable all of the rules that you would like to use.
8586
* [jsx-uses-react](docs/rules/jsx-uses-react.md): Prevent React to be incorrectly marked as unused
8687
* [jsx-uses-vars](docs/rules/jsx-uses-vars.md): Prevent variables used in JSX to be incorrectly marked as unused
8788
* [no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
89+
* [no-set-state](docs/rules/no-set-state.md): Prevent usage of setState
8890
* [no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of setState in componentDidMount
8991
* [no-did-update-set-state](docs/rules/no-did-update-set-state.md): Prevent usage of setState in componentDidUpdate
9092
* [no-multi-comp](docs/rules/no-multi-comp.md): Prevent multiple component definition per file

docs/rules/no-set-state.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Prevent usage of setState (no-set-state)
2+
3+
When using an architecture that separates your application state from your UI components (e.g. Flux), it may be desirable to forbid the use of local component state.
4+
5+
## Rule Details
6+
7+
The following patterns are considered warnings:
8+
9+
```js
10+
var Hello = React.createClass({
11+
getInitialState: function() {
12+
return {
13+
name: this.props.name
14+
};
15+
},
16+
handleClick: function() {
17+
this.setState({
18+
name: this.props.name.toUpperCase()
19+
});
20+
},
21+
render: function() {
22+
return <div onClick={this.handleClick.bind(this)}>Hello {this.state.name}</div>;
23+
}
24+
});
25+
```
26+
27+
The following patterns are not considered warnings:
28+
29+
```js
30+
var Hello = React.createClass({
31+
render: function() {
32+
return <div onClick={this.props.handleClick}>Hello {this.props.name}</div>;
33+
}
34+
});
35+
```

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module.exports = {
99
'wrap-multilines': require('./lib/rules/wrap-multilines'),
1010
'self-closing-comp': require('./lib/rules/self-closing-comp'),
1111
'no-danger': require('./lib/rules/no-danger'),
12+
'no-set-state': require('./lib/rules/no-set-state'),
1213
'no-did-mount-set-state': require('./lib/rules/no-did-mount-set-state'),
1314
'no-did-update-set-state': require('./lib/rules/no-did-update-set-state'),
1415
'react-in-jsx-scope': require('./lib/rules/react-in-jsx-scope'),
@@ -35,6 +36,7 @@ module.exports = {
3536
'wrap-multilines': 0,
3637
'self-closing-comp': 0,
3738
'no-danger': 0,
39+
'no-set-state': 0,
3840
'no-did-mount-set-state': 0,
3941
'no-did-update-set-state': 0,
4042
'react-in-jsx-scope': 0,

lib/rules/no-set-state.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @fileoverview Prevent usage of setState
3+
* @author Mark Dalgleish
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Rule Definition
9+
// ------------------------------------------------------------------------------
10+
11+
module.exports = function(context) {
12+
13+
// --------------------------------------------------------------------------
14+
// Public
15+
// --------------------------------------------------------------------------
16+
17+
return {
18+
19+
CallExpression: function(node) {
20+
var callee = node.callee;
21+
if (callee.type !== 'MemberExpression') {
22+
return;
23+
}
24+
if (callee.object.type !== 'ThisExpression' || callee.property.name !== 'setState') {
25+
return;
26+
}
27+
var ancestors = context.getAncestors(callee);
28+
for (var i = 0, j = ancestors.length; i < j; i++) {
29+
if (ancestors[i].type === 'Property' || ancestors[i].type === 'MethodDefinition') {
30+
context.report(callee, 'Do not use setState');
31+
break;
32+
}
33+
}
34+
}
35+
};
36+
37+
};
38+
39+
module.exports.schema = [];

tests/lib/rules/no-set-state.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* @fileoverview Prevent usage of setState
3+
* @author Mark Dalgleish
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../../../lib/rules/no-set-state');
12+
var RuleTester = require('eslint').RuleTester;
13+
14+
// ------------------------------------------------------------------------------
15+
// Tests
16+
// ------------------------------------------------------------------------------
17+
18+
var ruleTester = new RuleTester();
19+
ruleTester.run('no-set-state', rule, {
20+
21+
valid: [{
22+
code: [
23+
'var Hello = function() {',
24+
' this.setState({})',
25+
'};'
26+
].join('\n'),
27+
ecmaFeatures: {}
28+
}, {
29+
code: [
30+
'var Hello = React.createClass({',
31+
' render: function() {',
32+
' return <div>Hello {this.props.name}</div>;',
33+
' }',
34+
'});'
35+
].join('\n'),
36+
ecmaFeatures: {
37+
jsx: true
38+
}
39+
}, {
40+
code: [
41+
'var Hello = React.createClass({',
42+
' componentDidUpdate: function() {',
43+
' someNonMemberFunction(arg);',
44+
' this.someHandler = this.setState;',
45+
' },',
46+
' render: function() {',
47+
' return <div>Hello {this.props.name}</div>;',
48+
' }',
49+
'});'
50+
].join('\n'),
51+
ecmaFeatures: {
52+
jsx: true
53+
}
54+
}],
55+
56+
invalid: [{
57+
code: [
58+
'var Hello = React.createClass({',
59+
' componentDidUpdate: function() {',
60+
' this.setState({',
61+
' name: this.props.name.toUpperCase()',
62+
' });',
63+
' },',
64+
' render: function() {',
65+
' return <div>Hello {this.state.name}</div>;',
66+
' }',
67+
'});'
68+
].join('\n'),
69+
ecmaFeatures: {
70+
jsx: true
71+
},
72+
errors: [{
73+
message: 'Do not use setState'
74+
}]
75+
}, {
76+
code: [
77+
'var Hello = React.createClass({',
78+
' someMethod: function() {',
79+
' this.setState({',
80+
' name: this.props.name.toUpperCase()',
81+
' });',
82+
' },',
83+
' render: function() {',
84+
' return <div onClick={this.someMethod.bind(this)}>Hello {this.state.name}</div>;',
85+
' }',
86+
'});'
87+
].join('\n'),
88+
ecmaFeatures: {
89+
jsx: true
90+
},
91+
errors: [{
92+
message: 'Do not use setState'
93+
}]
94+
}, {
95+
code: [
96+
'class Hello extends React.Component {',
97+
' someMethod() {',
98+
' this.setState({',
99+
' name: this.props.name.toUpperCase()',
100+
' });',
101+
' }',
102+
' render() {',
103+
' return <div onClick={this.someMethod.bind(this)}>Hello {this.state.name}</div>;',
104+
' }',
105+
'};'
106+
].join('\n'),
107+
ecmaFeatures: {
108+
jsx: true,
109+
classes: true
110+
},
111+
errors: [{
112+
message: 'Do not use setState'
113+
}]
114+
}]
115+
});

0 commit comments

Comments
 (0)