Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add no-set-state rule #197

Merged
merged 1 commit into from
Aug 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Finally, enable all of the rules that you would like to use.
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/no-danger": 1,
"react/no-set-state": 1,
"react/no-did-mount-set-state": 1,
"react/no-did-update-set-state": 1,
"react/no-multi-comp": 1,
Expand Down Expand Up @@ -85,6 +86,7 @@ Finally, enable all of the rules that you would like to use.
* [jsx-uses-react](docs/rules/jsx-uses-react.md): Prevent React to be incorrectly marked as unused
* [jsx-uses-vars](docs/rules/jsx-uses-vars.md): Prevent variables used in JSX to be incorrectly marked as unused
* [no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
* [no-set-state](docs/rules/no-set-state.md): Prevent usage of setState
* [no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of setState in componentDidMount
* [no-did-update-set-state](docs/rules/no-did-update-set-state.md): Prevent usage of setState in componentDidUpdate
* [no-multi-comp](docs/rules/no-multi-comp.md): Prevent multiple component definition per file
Expand Down
35 changes: 35 additions & 0 deletions docs/rules/no-set-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Prevent usage of setState (no-set-state)

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.

## Rule Details

The following patterns are considered warnings:

```js
var Hello = React.createClass({
getInitialState: function() {
return {
name: this.props.name
};
},
handleClick: function() {
this.setState({
name: this.props.name.toUpperCase()
});
},
render: function() {
return <div onClick={this.handleClick.bind(this)}>Hello {this.state.name}</div>;
}
});
```

The following patterns are not considered warnings:

```js
var Hello = React.createClass({
render: function() {
return <div onClick={this.props.handleClick}>Hello {this.props.name}</div>;
}
});
```
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
'wrap-multilines': require('./lib/rules/wrap-multilines'),
'self-closing-comp': require('./lib/rules/self-closing-comp'),
'no-danger': require('./lib/rules/no-danger'),
'no-set-state': require('./lib/rules/no-set-state'),
'no-did-mount-set-state': require('./lib/rules/no-did-mount-set-state'),
'no-did-update-set-state': require('./lib/rules/no-did-update-set-state'),
'react-in-jsx-scope': require('./lib/rules/react-in-jsx-scope'),
Expand All @@ -35,6 +36,7 @@ module.exports = {
'wrap-multilines': 0,
'self-closing-comp': 0,
'no-danger': 0,
'no-set-state': 0,
'no-did-mount-set-state': 0,
'no-did-update-set-state': 0,
'react-in-jsx-scope': 0,
Expand Down
39 changes: 39 additions & 0 deletions lib/rules/no-set-state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @fileoverview Prevent usage of setState
* @author Mark Dalgleish
*/
'use strict';

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = function(context) {

// --------------------------------------------------------------------------
// Public
// --------------------------------------------------------------------------

return {

CallExpression: function(node) {
var callee = node.callee;
if (callee.type !== 'MemberExpression') {
return;
}
if (callee.object.type !== 'ThisExpression' || callee.property.name !== 'setState') {
return;
}
var ancestors = context.getAncestors(callee);
for (var i = 0, j = ancestors.length; i < j; i++) {
if (ancestors[i].type === 'Property' || ancestors[i].type === 'MethodDefinition') {
context.report(callee, 'Do not use setState');
break;
}
}
}
};

};

module.exports.schema = [];
115 changes: 115 additions & 0 deletions tests/lib/rules/no-set-state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* @fileoverview Prevent usage of setState
* @author Mark Dalgleish
*/
'use strict';

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

var rule = require('../../../lib/rules/no-set-state');
var RuleTester = require('eslint').RuleTester;

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

var ruleTester = new RuleTester();
ruleTester.run('no-set-state', rule, {

valid: [{
code: [
'var Hello = function() {',
' this.setState({})',
'};'
].join('\n'),
ecmaFeatures: {}
}, {
code: [
'var Hello = React.createClass({',
' render: function() {',
' return <div>Hello {this.props.name}</div>;',
' }',
'});'
].join('\n'),
ecmaFeatures: {
jsx: true
}
}, {
code: [
'var Hello = React.createClass({',
' componentDidUpdate: function() {',
' someNonMemberFunction(arg);',
' this.someHandler = this.setState;',
' },',
' render: function() {',
' return <div>Hello {this.props.name}</div>;',
' }',
'});'
].join('\n'),
ecmaFeatures: {
jsx: true
}
}],

invalid: [{
code: [
'var Hello = React.createClass({',
' componentDidUpdate: function() {',
' this.setState({',
' name: this.props.name.toUpperCase()',
' });',
' },',
' render: function() {',
' return <div>Hello {this.state.name}</div>;',
' }',
'});'
].join('\n'),
ecmaFeatures: {
jsx: true
},
errors: [{
message: 'Do not use setState'
}]
}, {
code: [
'var Hello = React.createClass({',
' someMethod: function() {',
' this.setState({',
' name: this.props.name.toUpperCase()',
' });',
' },',
' render: function() {',
' return <div onClick={this.someMethod.bind(this)}>Hello {this.state.name}</div>;',
' }',
'});'
].join('\n'),
ecmaFeatures: {
jsx: true
},
errors: [{
message: 'Do not use setState'
}]
}, {
code: [
'class Hello extends React.Component {',
' someMethod() {',
' this.setState({',
' name: this.props.name.toUpperCase()',
' });',
' }',
' render() {',
' return <div onClick={this.someMethod.bind(this)}>Hello {this.state.name}</div>;',
' }',
'};'
].join('\n'),
ecmaFeatures: {
jsx: true,
classes: true
},
errors: [{
message: 'Do not use setState'
}]
}]
});