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-unused-state #1103

Merged
merged 6 commits into from Jul 21, 2017
Merged

Conversation

wbinnssmith
Copy link
Contributor

Link to significant commit is here

This adds a new rule, react/no-unused-state, which discovers state fields in a React component and warns if any of them are never read. It was developed internally at Facebook by @rjbailey and has been in use throughout Facebook's JS for a couple months now. It was written against a modern version of node, so has been rebased on @ljharb's branch dropping support for node < 4.

It currently supports es2015 classes extending React.Component (no support currently for React.createClass()) and can detect when state is as this.state = {}, assigning state in a property initializer, and when calling this.setState().

@wbinnssmith
Copy link
Contributor Author

I'm happy to port down to node 0.10 to get this merged sooner, but would rather #1038 be merged :)

@ljharb
Copy link
Member

ljharb commented Mar 7, 2017

Yes, please do that. It will take much longer if it needs to wait for a major release, and this PR's diff will be cleaner.

@wbinnssmith wbinnssmith force-pushed the wbinnssmith/no-unused-state branch 2 times, most recently from 7ba0eaa to 4ddb0ff Compare March 10, 2017 00:37
@wbinnssmith
Copy link
Contributor Author

Rebased and ported back to node 0.10

How do you feel about the lack of support for React.createClass()?

@ianobermiller
Copy link

It currently supports es2015 classes extending React.Component

To clarify, it actually supports ANY class that has a render method, no matter what it extends from.

ljharb
ljharb previously requested changes Mar 11, 2017
Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since createClass still works and is supported by this plugin, I think it also needs to be handled.

As for the other point - many things have a render method that aren't React components. Please use the component detection utility functions that all of our rules use, and you should be able to cover all kinds of components without extra work.

@wbinnssmith
Copy link
Contributor Author

Addressed the feedback and implemented createClass support. Components util made quick work of it -- awesome.

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! This LGTM but I'm going to defer to other reviewers for the final stamp :-)

var isDirectStateReference =
node.type === 'MemberExpression' &&
isThisExpression(node.object) &&
node.property.name === 'state';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will every node have a property property? If not, the .name could crash when encountering unexpected node types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every MemberExpression should, yeah, which should be limited by the prior condition. cc @rjbailey

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, every MemberExpression should have a property AFAIK. It may not have a name (if it's computed), but it won't crash.

If we used getName(node.property) === 'state' instead we'd also handle the computed case (so we'd detect uses like this['state']). Looks like I forgot to do that here :)

@ljharb ljharb dismissed their stale review March 13, 2017 01:19

deferring to other reviewers

@ljharb
Copy link
Member

ljharb commented Apr 22, 2017

@yannickcr @lencioni @EvNaverniouk ping for review

@danielheyman
Copy link

Any update on this rule?

@ljharb
Copy link
Member

ljharb commented Jul 3, 2017

@wbinnssmith would you mind freshly rebasing this? after that, i'll give it a rereview, and then merge ASAP if there's no objections from other collabs.

@wbinnssmith
Copy link
Contributor Author

@ljharb no problem :)

@wbinnssmith
Copy link
Contributor Author

okay @ljharb, just rebased, cleaned things up, and moved some stuff back to node 4 compatible features (where this all started 😂)

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM


const eslintTester = new RuleTester({
parserOptions: parserOptions,
parser: 'babel-eslint'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is babel-eslint needed for all these test cases? It'd be ideal to use the default parser whenever possible.

@wbinnssmith
Copy link
Contributor Author

I can split the tests up using multiple RuleTesters, separating those that parse js compatible with espree + es2015, and those that require babylon with support for experimental features enabled (property initializers and object spread, mainly). Does that sound useful?

@ljharb
Copy link
Member

ljharb commented Jul 12, 2017

You don't need to create a new RuleTester instance - the constructor argument is just the default parser options; each valid/invalid example can also provide its own parser options.

@wbinnssmith
Copy link
Contributor Author

@ljharb that's exactly what I ended up doing :)

ping @yannickcr @lencioni @EvHaus

@wbinnssmith
Copy link
Contributor Author

ping! can @yannickcr @lencioni or @EvHaus look at this please?

@ljharb
Copy link
Member

ljharb commented Jul 20, 2017

Sorry for the inconvenience; I've just merged a refactor to start using arrow functions. Would you mind rebasing?

I'll merge within the next day or two, if no objections, after that's done.

Copy link
Collaborator

@EvHaus EvHaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

This adds a new rule, react/no-unused-state, which discovers state fields in a React component and warns if any of them are never read. It was developed internally at Facebook by @rjbailey and has been in use throughout Facebook's JS for a couple months now. It was written against a modern version of node, so has been rebased on @jlharb's branch dropping support for node < 4.

It currently supports es2015 classes extending `React.Component`  (no support currently for `React.createClass()`) and can detect when state is as `this.state = {}`, assigning state in a property initializer, and when calling `this.setState()`.
@wbinnssmith
Copy link
Contributor Author

done.

@ljharb ljharb merged commit 8bfafe1 into jsx-eslint:master Jul 21, 2017
@wbinnssmith
Copy link
Contributor Author

🎉 Thanks for your help throughout the process, @ljharb!

@ljharb
Copy link
Member

ljharb commented Aug 10, 2017

Whoops, this needs documentation. @wbinnssmith, if you could file a PR to fix #1351, that'd be great!

github-actions bot pushed a commit to capitnflam/eslint-plugin that referenced this pull request Mar 16, 2024
# [1.1.0](v1.0.1...v1.1.0) (2024-03-16)

### chore

* **deps-dev:** bump [@types](https://github.com/types)/node from 20.11.27 to 20.11.28 ([#13](#13)) ([738e28c](738e28c))
* **deps:** bump eslint-plugin-react from 7.34.0 to 7.34.1 ([#12](#12)) ([ad9f1b3](ad9f1b3)), closes [#3700](https://github.com/capitnflam/eslint-plugin/issues/3700) [#3701](https://github.com/capitnflam/eslint-plugin/issues/3701) [#3704](https://github.com/capitnflam/eslint-plugin/issues/3704) [#3705](https://github.com/capitnflam/eslint-plugin/issues/3705) [#3707](https://github.com/capitnflam/eslint-plugin/issues/3707) [#3713](https://github.com/capitnflam/eslint-plugin/issues/3713) [#3715](https://github.com/capitnflam/eslint-plugin/issues/3715) [#1000](https://github.com/capitnflam/eslint-plugin/issues/1000) [jsx-eslint/eslint-plugin-react#1000](jsx-eslint/eslint-plugin-react#1000) [#1002](https://github.com/capitnflam/eslint-plugin/issues/1002) [jsx-eslint/eslint-plugin-react#1002](jsx-eslint/eslint-plugin-react#1002) [#1005](https://github.com/capitnflam/eslint-plugin/issues/1005) [jsx-eslint/eslint-plugin-react#1005](jsx-eslint/eslint-plugin-react#1005) [#100](https://github.com/capitnflam/eslint-plugin/issues/100) [jsx-eslint/eslint-plugin-react#100](jsx-eslint/eslint-plugin-react#100) [#1010](https://github.com/capitnflam/eslint-plugin/issues/1010) [jsx-eslint/eslint-plugin-react#1010](jsx-eslint/eslint-plugin-react#1010) [#1013](https://github.com/capitnflam/eslint-plugin/issues/1013) [jsx-eslint/eslint-plugin-react#1013](jsx-eslint/eslint-plugin-react#1013) [#1022](https://github.com/capitnflam/eslint-plugin/issues/1022) [jsx-eslint/eslint-plugin-react#1022](jsx-eslint/eslint-plugin-react#1022) [#1029](https://github.com/capitnflam/eslint-plugin/issues/1029) [jsx-eslint/eslint-plugin-react#1029](jsx-eslint/eslint-plugin-react#1029) [#102](https://github.com/capitnflam/eslint-plugin/issues/102) [jsx-eslint/eslint-plugin-react#102](jsx-eslint/eslint-plugin-react#102) [#1034](https://github.com/capitnflam/eslint-plugin/issues/1034) [jsx-eslint/eslint-plugin-react#1034](jsx-eslint/eslint-plugin-react#1034) [#1038](https://github.com/capitnflam/eslint-plugin/issues/1038) [jsx-eslint/eslint-plugin-react#1038](jsx-eslint/eslint-plugin-react#1038) [#1041](https://github.com/capitnflam/eslint-plugin/issues/1041) [jsx-eslint/eslint-plugin-react#1041](jsx-eslint/eslint-plugin-react#1041) [#1043](https://github.com/capitnflam/eslint-plugin/issues/1043) [jsx-eslint/eslint-plugin-react#1043](jsx-eslint/eslint-plugin-react#1043) [#1046](https://github.com/capitnflam/eslint-plugin/issues/1046) [jsx-eslint/eslint-plugin-react#1046](jsx-eslint/eslint-plugin-react#1046) [#1047](https://github.com/capitnflam/eslint-plugin/issues/1047) [jsx-eslint/eslint-plugin-react#1047](jsx-eslint/eslint-plugin-react#1047) [#1050](https://github.com/capitnflam/eslint-plugin/issues/1050) [jsx-eslint/eslint-plugin-react#1050](jsx-eslint/eslint-plugin-react#1050) [#1053](https://github.com/capitnflam/eslint-plugin/issues/1053) [jsx-eslint/eslint-plugin-react#1053](jsx-eslint/eslint-plugin-react#1053) [#1057](https://github.com/capitnflam/eslint-plugin/issues/1057) [jsx-eslint/eslint-plugin-react#1057](jsx-eslint/eslint-plugin-react#1057) [#105](https://github.com/capitnflam/eslint-plugin/issues/105) [jsx-eslint/eslint-plugin-react#105](jsx-eslint/eslint-plugin-react#105) [#1061](https://github.com/capitnflam/eslint-plugin/issues/1061) [jsx-eslint/eslint-plugin-react#1061](jsx-eslint/eslint-plugin-react#1061) [#1062](https://github.com/capitnflam/eslint-plugin/issues/1062) [jsx-eslint/eslint-plugin-react#1062](jsx-eslint/eslint-plugin-react#1062) [#1070](https://github.com/capitnflam/eslint-plugin/issues/1070) [jsx-eslint/eslint-plugin-react#1070](jsx-eslint/eslint-plugin-react#1070) [#1071](https://github.com/capitnflam/eslint-plugin/issues/1071) [jsx-eslint/eslint-plugin-react#1071](jsx-eslint/eslint-plugin-react#1071) [#1073](https://github.com/capitnflam/eslint-plugin/issues/1073) [jsx-eslint/eslint-plugin-react#1073](jsx-eslint/eslint-plugin-react#1073) [#1076](https://github.com/capitnflam/eslint-plugin/issues/1076) [jsx-eslint/eslint-plugin-react#1076](jsx-eslint/eslint-plugin-react#1076) [#1079](https://github.com/capitnflam/eslint-plugin/issues/1079) [jsx-eslint/eslint-plugin-react#1079](jsx-eslint/eslint-plugin-react#1079) [#1088](https://github.com/capitnflam/eslint-plugin/issues/1088) [jsx-eslint/eslint-plugin-react#1088](jsx-eslint/eslint-plugin-react#1088) [#1098](https://github.com/capitnflam/eslint-plugin/issues/1098) [jsx-eslint/eslint-plugin-react#1098](jsx-eslint/eslint-plugin-react#1098) [#1101](https://github.com/capitnflam/eslint-plugin/issues/1101) [jsx-eslint/eslint-plugin-react#1101](jsx-eslint/eslint-plugin-react#1101) [#1103](https://github.com/capitnflam/eslint-plugin/issues/1103) [jsx-eslint/eslint-plugin-react#1103](jsx-eslint/eslint-plugin-react#1103) [#110](https://github.com/capitnflam/eslint-plugin/issues/110) [jsx-eslint/eslint-plugin-react#110](jsx-eslint/eslint-plugin-react#110) [#1116](https://github.com/capitnflam/eslint-plugin/issues/1116) [jsx-eslint/eslint-plugin-react#1116](jsx-eslint/eslint-plugin-react#1116) [#1117](https://github.com/capitnflam/eslint-plugin/issues/1117) [jsx-eslint/eslint-plugin-react#1117](jsx-eslint/eslint-plugin-react#1117) [#1119](https://github.com/capitnflam/eslint-plugin/issues/1119) [jsx-eslint/eslint-plugin-react#1119](jsx-eslint/eslint-plugin-react#1119) [#1121](https://github.com/capitnflam/eslint-plugin/issues/1121) [jsx-eslint/eslint-plugin-react#1121](jsx-eslint/eslint-plugin-react#1121) [#1122](https://github.com/capitnflam/eslint-plugin/issues/1122) [jsx-eslint/eslint-plugin-react#1122](jsx-eslint/eslint-plugin-react#1122) [#1123](https://github.com/capitnflam/eslint-plugin/issues/1123) [jsx-eslint/eslint-plugin-react#1123](jsx-eslint/eslint-plugin-react#1123) [#3700](https://github.com/capitnflam/eslint-plugin/issues/3700) [#3701](https://github.com/capitnflam/eslint-plugin/issues/3701) [#3704](https://github.com/capitnflam/eslint-plugin/issues/3704) [#3705](https://github.com/capitnflam/eslint-plugin/issues/3705) [#3707](https://github.com/capitnflam/eslint-plugin/issues/3707) [#3713](https://github.com/capitnflam/eslint-plugin/issues/3713) [#3715](https://github.com/capitnflam/eslint-plugin/issues/3715) [#3715](https://github.com/capitnflam/eslint-plugin/issues/3715) [jsx-eslint/eslint-plugin-react#3715](jsx-eslint/eslint-plugin-react#3715) [#3713](https://github.com/capitnflam/eslint-plugin/issues/3713) [jsx-eslint/eslint-plugin-react#3713](jsx-eslint/eslint-plugin-react#3713) [#3707](https://github.com/capitnflam/eslint-plugin/issues/3707) [jsx-eslint/eslint-plugin-react#3707](jsx-eslint/eslint-plugin-react#3707) [#3705](https://github.com/capitnflam/eslint-plugin/issues/3705) [jsx-eslint/eslint-plugin-react#3705](jsx-eslint/eslint-plugin-react#3705) [#3704](https://github.com/capitnflam/eslint-plugin/issues/3704) [jsx-eslint/eslint-plugin-react#3704](jsx-eslint/eslint-plugin-react#3704) [#3701](https://github.com/capitnflam/eslint-plugin/issues/3701) [jsx-eslint/eslint-plugin-react#3701](jsx-eslint/eslint-plugin-react#3701) [#3700](https://github.com/capitnflam/eslint-plugin/issues/3700) [jsx-eslint/eslint-plugin-react#3700](jsx-eslint/eslint-plugin-react#3700)

### ci

* add auto assign action ([#14](#14)) ([07d1f9a](07d1f9a))
* add check workflow ([#11](#11)) ([8afc82a](8afc82a))

### feat

* add [@eslint-community](https://github.com/eslint-community)/eslint-plugin-eslint-comments ([#17](#17)) ([fe2bf30](fe2bf30))
* add eslint-plugin-n ([#18](#18)) ([203d603](203d603))
* add eslint-plugin-security ([#16](#16)) ([e7f8c2e](e7f8c2e))
* add eslint-plugin-sonarjs ([#15](#15)) ([5bca4e1](5bca4e1))
* **react:** add some security linting ([#10](#10)) ([4424b67](4424b67))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

None yet

6 participants