Skip to content

Commit fca4db0

Browse files
committed
Add allow-in-func option to no-did-update-set-state (fixes #300)
1 parent 48f67ad commit fca4db0

File tree

2 files changed

+183
-21
lines changed

2 files changed

+183
-21
lines changed

lib/rules/no-did-update-set-state.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
module.exports = function(context) {
1212

13+
var mode = context.options[0] || 'never';
14+
1315
// --------------------------------------------------------------------------
1416
// Public
1517
// --------------------------------------------------------------------------
@@ -18,25 +20,34 @@ module.exports = function(context) {
1820

1921
CallExpression: function(node) {
2022
var callee = node.callee;
21-
if (callee.type !== 'MemberExpression') {
22-
return;
23-
}
24-
if (callee.object.type !== 'ThisExpression' || callee.property.name !== 'setState') {
23+
if (
24+
callee.type !== 'MemberExpression' ||
25+
callee.object.type !== 'ThisExpression' ||
26+
callee.property.name !== 'setState'
27+
) {
2528
return;
2629
}
27-
var ancestors = context.getAncestors(callee);
30+
var ancestors = context.getAncestors(callee).reverse();
31+
var depth = 0;
2832
for (var i = 0, j = ancestors.length; i < j; i++) {
33+
if (/Function(Expression|Declaration)$/.test(ancestors[i].type)) {
34+
depth++;
35+
}
2936
if (
3037
(ancestors[i].type !== 'Property' && ancestors[i].type !== 'MethodDefinition') ||
31-
ancestors[i].key.name !== 'componentDidUpdate'
38+
ancestors[i].key.name !== 'componentDidUpdate' ||
39+
(mode === 'allow-in-func' && depth > 1)
3240
) {
3341
continue;
3442
}
3543
context.report(callee, 'Do not use setState in componentDidUpdate');
44+
break;
3645
}
3746
}
3847
};
3948

4049
};
4150

42-
module.exports.schema = [];
51+
module.exports.schema = [{
52+
enum: ['allow-in-func']
53+
}];

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

Lines changed: 165 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
var rule = require('../../../lib/rules/no-did-update-set-state');
1212
var RuleTester = require('eslint').RuleTester;
1313

14+
require('babel-eslint');
15+
1416
// ------------------------------------------------------------------------------
1517
// Tests
1618
// ------------------------------------------------------------------------------
@@ -32,10 +34,7 @@ ruleTester.run('no-did-update-set-state', rule, {
3234
}, {
3335
code: [
3436
'var Hello = React.createClass({',
35-
'componentDidUpdate: function() {},',
36-
' render: function() {',
37-
' return <div>Hello {this.props.name}</div>;',
38-
' }',
37+
' componentDidUpdate: function() {}',
3938
'});'
4039
].join('\n'),
4140
ecmaFeatures: {
@@ -47,30 +46,89 @@ ruleTester.run('no-did-update-set-state', rule, {
4746
' componentDidUpdate: function() {',
4847
' someNonMemberFunction(arg);',
4948
' this.someHandler = this.setState;',
50-
' },',
51-
' render: function() {',
52-
' return <div>Hello {this.props.name}</div>;',
5349
' }',
5450
'});'
5551
].join('\n'),
5652
ecmaFeatures: {
5753
jsx: true
5854
}
55+
}, {
56+
code: [
57+
'var Hello = React.createClass({',
58+
' componentDidUpdate: function() {',
59+
' someClass.onSomeEvent(function(data) {',
60+
' this.setState({',
61+
' data: data',
62+
' });',
63+
' })',
64+
' }',
65+
'});'
66+
].join('\n'),
67+
options: ['allow-in-func'],
68+
ecmaFeatures: {
69+
jsx: true
70+
}
71+
}, {
72+
code: [
73+
'var Hello = React.createClass({',
74+
' componentDidUpdate: function() {',
75+
' function handleEvent(data) {',
76+
' this.setState({',
77+
' data: data',
78+
' });',
79+
' }',
80+
' someClass.onSomeEvent(handleEvent)',
81+
' }',
82+
'});'
83+
].join('\n'),
84+
parser: 'babel-eslint',
85+
options: ['allow-in-func'],
86+
ecmaFeatures: {
87+
jsx: true
88+
}
5989
}],
6090

6191
invalid: [{
6292
code: [
6393
'var Hello = React.createClass({',
6494
' componentDidUpdate: function() {',
6595
' this.setState({',
66-
' name: this.props.name.toUpperCase()',
96+
' data: data',
97+
' });',
98+
' }',
99+
'});'
100+
].join('\n'),
101+
ecmaFeatures: {
102+
jsx: true
103+
},
104+
errors: [{
105+
message: 'Do not use setState in componentDidUpdate'
106+
}]
107+
}, {
108+
code: [
109+
'class Hello extends React.Component {',
110+
' componentDidUpdate() {',
111+
' this.setState({',
112+
' data: data',
113+
' });',
114+
' }',
115+
'}'
116+
].join('\n'),
117+
parser: 'babel-eslint',
118+
errors: [{
119+
message: 'Do not use setState in componentDidUpdate'
120+
}]
121+
}, {
122+
code: [
123+
'var Hello = React.createClass({',
124+
' componentDidUpdate: function() {',
125+
' this.setState({',
126+
' data: data',
67127
' });',
68-
' },',
69-
' render: function() {',
70-
' return <div>Hello {this.state.name}</div>;',
71128
' }',
72129
'});'
73130
].join('\n'),
131+
options: ['allow-in-func'],
74132
ecmaFeatures: {
75133
jsx: true
76134
},
@@ -82,11 +140,104 @@ ruleTester.run('no-did-update-set-state', rule, {
82140
'class Hello extends React.Component {',
83141
' componentDidUpdate() {',
84142
' this.setState({',
85-
' name: this.props.name.toUpperCase()',
143+
' data: data',
86144
' });',
87145
' }',
88-
' render() {',
89-
' return <div>Hello {this.state.name}</div>;',
146+
'}'
147+
].join('\n'),
148+
parser: 'babel-eslint',
149+
options: ['allow-in-func'],
150+
errors: [{
151+
message: 'Do not use setState in componentDidUpdate'
152+
}]
153+
}, {
154+
code: [
155+
'var Hello = React.createClass({',
156+
' componentDidUpdate: function() {',
157+
' someClass.onSomeEvent(function(data) {',
158+
' this.setState({',
159+
' data: data',
160+
' });',
161+
' })',
162+
' }',
163+
'});'
164+
].join('\n'),
165+
ecmaFeatures: {
166+
jsx: true
167+
},
168+
errors: [{
169+
message: 'Do not use setState in componentDidUpdate'
170+
}]
171+
}, {
172+
code: [
173+
'class Hello extends React.Component {',
174+
' componentDidUpdate() {',
175+
' someClass.onSomeEvent(function(data) {',
176+
' this.setState({',
177+
' data: data',
178+
' });',
179+
' })',
180+
' }',
181+
'}'
182+
].join('\n'),
183+
parser: 'babel-eslint',
184+
errors: [{
185+
message: 'Do not use setState in componentDidUpdate'
186+
}]
187+
}, {
188+
code: [
189+
'var Hello = React.createClass({',
190+
' componentDidUpdate: function() {',
191+
' if (true) {',
192+
' this.setState({',
193+
' data: data',
194+
' });',
195+
' }',
196+
' }',
197+
'});'
198+
].join('\n'),
199+
ecmaFeatures: {
200+
jsx: true
201+
},
202+
errors: [{
203+
message: 'Do not use setState in componentDidUpdate'
204+
}]
205+
}, {
206+
code: [
207+
'class Hello extends React.Component {',
208+
' componentDidUpdate() {',
209+
' if (true) {',
210+
' this.setState({',
211+
' data: data',
212+
' });',
213+
' }',
214+
' }',
215+
'}'
216+
].join('\n'),
217+
parser: 'babel-eslint',
218+
errors: [{
219+
message: 'Do not use setState in componentDidUpdate'
220+
}]
221+
}, {
222+
code: [
223+
'var Hello = React.createClass({',
224+
' componentDidUpdate: function() {',
225+
' someClass.onSomeEvent((data) => this.setState({data: data}));',
226+
' }',
227+
'});'
228+
].join('\n'),
229+
parser: 'babel-eslint',
230+
ecmaFeatures: {
231+
jsx: true
232+
},
233+
errors: [{
234+
message: 'Do not use setState in componentDidUpdate'
235+
}]
236+
}, {
237+
code: [
238+
'class Hello extends React.Component {',
239+
' componentDidUpdate() {',
240+
' someClass.onSomeEvent((data) => this.setState({data: data}));',
90241
' }',
91242
'}'
92243
].join('\n'),

0 commit comments

Comments
 (0)