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

Extract duplicate code between prop-types and no-unused-prop-types #1 #1536

Closed
wants to merge 6 commits into from

Conversation

jseminck
Copy link
Contributor

Follow-up for: #1526

Basically in prop-types and no-unused-prop-types there is quite a bit of duplicate code. I tried to do a HUGE refactoring to remove a lot of it but it turned out... well... not good 😄 So maybe smaller PRs is a better idea.

Basically made the "are we in a lifecycle method" detection similar between prop-types and no-unused-prop-types. Both rules were doing it differently but the results were the same. There was also duplicated methods like inComponentWillReceiveProps.

There should be some new cases detected now, e.g. in prop-types rule: nextProps should be considered not only for componentWillReceiveProps, but also for shouldComponentUpdate.

On that note, I noticed that prevProps is not supported for prop-types rule, with a lifecycle method of componentDidUpdate for example. There's some further refactoring needed to align the two rules more to get that properly working which I'd like to tackle in a PR after this.

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.

Just in the beginning, I'm a little concerned about the conflation of "is in a lifecycle method" with "is in the constructor" - could we start by keeping those separate, so the refactor is more 1-to-1?

@@ -1058,7 +989,7 @@ module.exports = {
ObjectPattern: function(node) {
// If the object pattern is a destructured props object in a lifecycle
// method -- mark it for used props.
if (isNodeALifeCycleMethod(node.parent.parent)) {
if (astUtil.inLifeCycleMethod(context)) {
Copy link
Member

Choose a reason for hiding this comment

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

is this necessarily equivalent? context.getScope() won't be the same as node.parent.parent, necessarily.

@jseminck
Copy link
Contributor Author

Thanks for feedback. I'm at a conference for the next 2 days, but I will make "is in constructor" separately and deeper investigate the differences isNodeALifeCycleMethod(node.parent.parent) vs astUtil.inLifeCycleMethod(context), which I do believe achieve the same thing, but technically they are doing something different.

@jseminck jseminck changed the title Duplicate code 1 Extract duplicate code between prop-types and no-unused-prop-types #1 Nov 16, 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.

LGTM! For posterity, could you reply to my comments with a link to the lines of code for the test cases in question?

const genericDestructuring =
isPropAttributeName(node) && (
utils.getParentStatelessComponent() ||
astUtil.inConstructor(context) ||
Copy link
Member

Choose a reason for hiding this comment

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

which test case exposes this missing inConstructor check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that the old isInLifeCycleMethod function already was checking whether we are in constructor: node.kind === 'constructor'. Now it is split into inConstructor and inLifecycleMethod so the code is the same between this rule and prop-types.

In this case, the following two tests will fail when removing this line:

@@ -992,7 +928,8 @@ module.exports = {
// let {firstname} = props
const statelessDestructuring = destructuring && isPropAttributeName(node) && (
utils.getParentStatelessComponent() ||
isInLifeCycleMethod(node)
astUtil.inConstructor(context) ||
Copy link
Member

Choose a reason for hiding this comment

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

also here, which test case exposes the need for this check?

Copy link
Contributor Author

@jseminck jseminck Nov 18, 2017

Choose a reason for hiding this comment

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

Same as above: Note that the old isInLifeCycleMethod function already was checking whether we are in constructor: node.kind === 'constructor'. Now it is split into inConstructor and inLifecycleMethod so the code is the same between this rule and prop-types.

However, this case seems to be untested. 😞 In master we can remove this whole block and the tests still pass.

&& ( utils.getParentStatelessComponent() || isInLifeCycleMethod(node))

@@ -1058,7 +995,7 @@ module.exports = {
ObjectPattern: function(node) {
// If the object pattern is a destructured props object in a lifecycle
// method -- mark it for used props.
if (isNodeALifeCycleMethod(node.parent.parent)) {
if (astUtil.inConstructor(context) || astUtil.inLifeCycleMethod(context)) {
Copy link
Member

Choose a reason for hiding this comment

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

also here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above.

Fails when removing inConstructor:

When removing the inLifecycleMethod then 5 tests fail (2 for componentWillReceiveProps, 1 for shouldComponentUpdate and 2 for componentDidUpdate)

I suppose that we can also test https://reactjs.org/docs/react-component.html#componentwillupdate which also has nextProps as the first argument.

@@ -967,7 +942,7 @@ module.exports = {
const directDestructuring =
destructuring &&
PROPS_REGEX.test(node.init.name) &&
(utils.getParentStatelessComponent() || inConstructor() || inComponentWillReceiveProps())
Copy link
Member

Choose a reason for hiding this comment

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

also, which test cases warrant this change from just checking willReceiveProps, to checking all the lifecycle methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is missing tests! Indeed we will now check more cases than just componentWillReceiveProps

@ljharb
Copy link
Member

ljharb commented Jan 4, 2019

@jseminck @alexzherdev is this PR still useful, now that #1911 and friends have landed?

@alexzherdev
Copy link
Contributor

It seems like what this PR contains has been achieved in spirit: there is now a single place that defines inConstructor and inLifecycleMethod, which is lib/util/usedPropTypes.js.

@ljharb
Copy link
Member

ljharb commented Jan 4, 2019

Are there test cases here we could salvage?

@jseminck jseminck closed this Jun 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants