Eslint-plugin-react: no-unused-prop-types sometimes fails to detect props in functions on stateless components

Created on 4 Oct 2016  路  29Comments  路  Source: yannickcr/eslint-plugin-react

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
bug

Most helpful comment

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.

All 29 comments

cc @oliviakim95

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.

Agreed.

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]
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.

@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.

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).

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

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

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

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.

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
}

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

You both may want to open another issue for componentWillReceiveProps

@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: https://github.com/yannickcr/eslint-plugin-react/issues/884#issuecomment-253903073

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

@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

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()
    }
  }

@wellingtonamaralleitao see #1232

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;

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

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)

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

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.

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

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

How it was not fixed in 4 years??

@GorgeousPuree the issue is closed, so it's fixed. if someone still has this problem on the latest version, please file a new issue and I'll be happy to take a look.

@ljharb I'm sorry, pal, my bad. I've just mixed up this issue with another, which looks almost the same.

Was this page helpful?
0 / 5 - 0 ratings