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

no-unused-prop-types sometimes fails to detect props in functions on stateless components #885

Closed
pfhayes opened this issue Oct 4, 2016 · 33 comments · Fixed by #946 or singapore/lint-condo#240
Labels

Comments

@pfhayes
Copy link
Contributor

pfhayes commented Oct 4, 2016

Here is a minimal example that triggers this:

const PagingBlock = function(props) {
  return (
    <span>
      <a onClick={() => props.previousPage()}/>
      <a onClick={() => props.nextPage()}/>
    </span>
 );
};

PagingBlock.propTypes = {
  nextPage: React.PropTypes.func.isRequired,
  previousPage: React.PropTypes.func.isRequired,
};

The error message is:

  18:17  error  'previousPage' PropType is defined but prop is never used  react/no-unused-prop-types

Notes:

  • Converting this to a React.createClass with static propTypes fixes the issue
  • Removing either <a/> tag produces the correct lint error, the false error only occurs when both are present
  • The error is notified for the first tag (switching nextPage and previousPage inside the render function will make the error text say nextPage is defined but not used
@pfhayes
Copy link
Contributor Author

pfhayes commented Oct 4, 2016

cc @oliviakim95

@EvHaus EvHaus added the bug label Oct 6, 2016
@LiJinyao
Copy link

LiJinyao commented Oct 8, 2016

this bug also triggers when use ...props.

const PagingBlock = function(props) {
  return (
    <SomeChild {...props} />
 );
};

PagingBlock.propTypes = {
  nextPage: React.PropTypes.func.isRequired,
  previousPage: React.PropTypes.func.isRequired,
};

The error message is the same.

I think we should count all properties as used in this case.

@ljharb
Copy link
Member

ljharb commented Oct 8, 2016

Agreed.

@tpai
Copy link

tpai commented Oct 11, 2016

Same issue...

export default function Content( { post } ) {
    const { title, author, body } = post;
    return (
        <Panel>
            <Article
              title={ title }
              meta={ author }
            >
                <div dangerouslySetInnerHTML={ { __html: body } } />
            </Article>
        </Panel>
    );
}

Content.propTypes = {
    post: PropTypes.shape( {
        title: PropTypes.string.isRequired,
        author: PropTypes.string.isRequired,
        body: PropTypes.string.isRequired,
    } ),
};
'post.title' PropType is defined but prop is never used (react/no-unused-prop-types) [javascript/eslint]
'post.author' PropType is defined but prop is never used (react/no-unused-prop-types) [javascript/eslint]
'post.body' PropType is defined but prop is never used (react/no-unused-prop-types) [javascript/eslint]

@xkr47
Copy link

xkr47 commented Oct 19, 2016

const FormInput = (props) => {
  const {
    input,
    type = "text",
    ...extraProps
  } = props;
  return (
    <div id={input.name + "_view"}>
       <input type={type} id={input.name} {...input} {...extraProps}/>
    </div>
  );
};

FormInput.propTypes = {
  input: React.PropTypes.object.isRequired,
  required: React.PropTypes.bool,
  type: React.PropTypes.string
};

-> complains that required is unused even if it gets used through extraProps.

@kevinSuttle
Copy link

kevinSuttle commented Oct 19, 2016

@xkr47 But it's not, though. How would ESlint know required, if it's not listed in the inline defaultProps literal or your return statement? It's throwing the error as it's listed in PropTypes, but nowhere else.

@ljharb
Copy link
Member

ljharb commented Oct 19, 2016

I think because extraProps is a rest arg, every prop in it should be marked as used (and it can be statically known in this case).

@xkr47
Copy link

xkr47 commented Oct 19, 2016

Agree with @ljharb although it's hard to say how far one should go tracing dependencies here..

@nowke
Copy link

nowke commented Oct 24, 2016

I have a similar problem with PropTypes.shape.

MyComponent.propTypes = {
  error: PropTypes.shape({
    username: PropTypes.string,
    password: PropTypes.string,
  }),
}

And I pass error to the child component as a whole.
<MyChildComponent error={this.props.error} />

ESLint throws

error  'error.username' PropType is defined but prop is never used  react/no-unused-prop-types
error  'error.password' PropType is defined but prop is never used  react/no-unused-prop-types

@devalnor
Copy link

devalnor commented Oct 26, 2016

Probably same issue...

import React, { PropTypes } from 'react';

export default function Article(props) {
    const {
        homepageThumb: {
            url: imageUrl,
            width: imageWidth,
            height: imageHeight
        }
    } = props;

    return (

        <img
            src={imageUrl}
            width={imageWidth}
            height={imageHeight}
            alt="thumb"
        />

    );
}

Article.propTypes = {
    homepageThumb: PropTypes.shape({
        url: PropTypes.string,
        width: PropTypes.number,
        height: PropTypes.number
    }).isRequired
};
  59:20  error    'thumbnail_images.homepage-thumb.width' PropType is defined but prop is never used   react/no-unused-prop-types
  60:21  error    'thumbnail_images.homepage-thumb.height' PropType is defined but prop is never used  react/no-unused-prop-types

@BarryThePenguin
Copy link
Contributor

BarryThePenguin commented Nov 7, 2016

I think I've figured out the source of this bug. Looking at @pfhayes example,

const PagingBlock = function(props) {
  return (
    <span>
      <a onClick={() => props.previousPage()}/>
      <a onClick={() => props.nextPage()}/>
    </span>
 );
};

PagingBlock.propTypes = {
  nextPage: React.PropTypes.func.isRequired,
  previousPage: React.PropTypes.func.isRequired,
};

It looks like when utils.getParentStatelessComponent() is called, the onClick ArrowFunctionExpression is returned instead of the PagingBlock FunctionExpression. In utils.getParentStatelessComponent() there is a regex test being performed on the Function keyword. This would return results for both FunctionExpression and ArrowFunctionExpression.

Need to find a way to differentiate between the two. I'll submit a PR if I can figure it out.

@iegik
Copy link

iegik commented Mar 12, 2017

Still throws error when:

static propTypes = {
    data: React.PropTypes.arrayOf(React.PropTypes.any).isRequired,
};

static defaultProps = {
    data: [],
};

componentWillReceiveProps(nextProps) {
    this.state.data = nextProps.data; // Here ESLint do not see usage of data prop
}

iegik added a commit to iegik/react-native-grid-component that referenced this issue Mar 12, 2017
@ahauser31
Copy link

Yeah, for me usage of a prop only in componentWillReceiveProps also throws this linting error.

@BarryThePenguin
Copy link
Contributor

You both may want to open another issue for componentWillReceiveProps

@borwahs
Copy link

borwahs commented Apr 25, 2017

@iegik & @ahauser31 -

I ran into the same issue and found that if you destructure nextProps instead of using dot notation, the linting error is not thrown.

I also confirmed in this thread: #884 (comment)

@geuis
Copy link

geuis commented May 24, 2017

Still getting this in the most recent version of eslint-plugin-react in exactly the same code situation as the original example.

@BarryThePenguin
Copy link
Contributor

@geuis there are tests for the exact same code situation as the original example.

If you have a different example that is still failing, would be worth opening a new issue

@wellyal
Copy link

wellyal commented Jun 1, 2017

Also failing to detect props being used on react lifecycle functions like

...
modalClosed: PropTypes.bool.isRequired
componentWillReceiveProps(nextProps) {
    if (nextProps.modalClosed) {
      this.props.router.goBack()
    }
  }

@ljharb
Copy link
Member

ljharb commented Jun 1, 2017

@wellingtonamaralleitao see #1232

@healqq
Copy link

healqq commented Jun 21, 2017

I might do something wrong but this shows onItemClick propType not to be used:

import React from 'react';
import PropTypes from 'prop-types';

import './List.css';

function List(props) {
  return (
    <div className="List">
        I am a list
        {
          props.items.map(item =>
            (<div className="List-item">
              <button onClick={() => props.onItemClick(item.id)}>{item.title} {item.isAdded}
              </button>
            </div>),
          )
        }
    </div>
  );
}

List.propTypes = {
  items: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number,
      title: PropTypes.string,
    }),
  ),
  onItemClick: PropTypes.func,
};
List.defaultProps = {
  items: [],
  onItemClick: null,
};
export default List;

@BarryThePenguin
Copy link
Contributor

@healqq looks legit. I'd recommend opening a new issue

@TrevorSayre
Copy link

TrevorSayre commented Jun 23, 2017

export default class Users extends Component {

  static propTypes = {
    ...
    onLoad: PropTypes.func.isRequired,
  };

  async componentWillMount() {
    await Promise.all([
      this.props.onLoad(),
      this.onSearch(),
    ]);
    ...
  }

  ...

}

'onLoad' PropType is defined but prop is never used (react/no-unused-prop-types)

@najinj
Copy link

najinj commented Sep 11, 2019

Using eslint-plugin-react v^7.14.3 still throw this error

@chinhoe
Copy link

chinhoe commented Sep 24, 2019

Experiencing the same issue too. Giving me an error saying 'PropType is defined but prop is never used' when my props is being used within a function inside a functional component.

@fiher
Copy link

fiher commented Nov 13, 2019

I have the same error too, I am passing a prop to a functional component and I define defaultProps so I can make sure it is always a function (it is not required prop) and it marks it as unused

@prateekmaheshwari
Copy link

I have the same error too with eslint-plugin-react v^7.19.0

@GorgeousPuree

This comment has been minimized.

@ljharb

This comment has been minimized.

@GorgeousPuree

This comment has been minimized.

@shashwata27
Copy link

shashwata27 commented Jul 26, 2021

React.PropTypes is deprecated since 15.5.
I'm getting the same error, of unused but defined.
here's my code.

import React from "react";
import bussinessIcon from "../icons/team-leader.svg";
import PropTypes from "prop-types";

People.propTypes = {
  id: PropTypes.number,
  details: PropTypes.object,
  deleteFunc: PropTypes.func,
  importantFunc: PropTypes.func,
};

export default class People extends React.Component {
  state = {
    visible: "",
    important: "",
  };

  handelDelete = () => {
    this.props.deleteFunc(this.props.id);
    // this.setState({ visible: "invisible" });
  };
  handelImportant = () => {
    this.props.importantFunc(this.props.id);
    this.state.important === ""
      ? this.setState({ important: "important" })
      : this.setState({ important: "" });
  };

  render() {
    const { name, work, city, phone, email } = this.props.details;

    return (
      <div className={`li ${this.state.visible} ${this.state.important}`}>
        <div className="liName">
          <span>{name}</span>
        </div>
        <div>
          <img src={bussinessIcon} alt="Bussiness Icon" />
          {`${work}, ${city}`}
        </div>
        <div className="personalInfo">{`${phone}     ${email}`}</div>
        <div className="buttons">
          <button onClick={this.handelImportant}>Important</button>
          <button onClick={this.handelDelete}>Delete</button>
          <button>Edit</button>
        </div>
      </div>
    );
  }
}

What am I doing wrong?

@ljharb
Copy link
Member

ljharb commented Jul 26, 2021

@shashwata27 theres no component in that code. Please file a new issue if you’re still having trouble.

@shashwata27
Copy link

@shashwata27 theres no component in that code. Please file a new issue if you’re still having trouble.

Check I updated the code above, should I make new issue?

@ljharb
Copy link
Member

ljharb commented Jul 26, 2021

Yes please; commenting on old closed issues is not an efficient way to get help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels