Eslint-plugin-react: False positive on `react/no-unused-prop-types`

Created on 11 Apr 2018  路  6Comments  路  Source: yannickcr/eslint-plugin-react

I came across some code looking like this where myProp was reportedly not being used, even though it was.

render() {
    const { props } = this;
    const { myProp } = props;
    someFunction(myProp)
}

MyComponent.propTypes = {
  myProp: PropTypes.number,
};

It seems the double desctructure confused the rule because a change to the code below fixed it.

render() {
    const { myProp } = this.props;
    someFunction(myProp)
}

I think it may be similar to https://github.com/yannickcr/eslint-plugin-react/issues/933, except this one is not such an anti-pattern. It looks very strange on my reduced version, but in a context with more variables can be more natural.

bug help wanted

Most helpful comment

Hello! Just showing my support for this bug to be fixed :-) :+1:

All 6 comments

I think destructuring props off of this is pretty rare, but i agree it should work.

In my case the code was better after the fix, but I agree it should work.

Hello! Just showing my support for this bug to be fixed :-) :+1:

Running into this all over our codebase. Here's a reduction of one of the cases, first the output, then the code:

C:\w\rnps-home-ui\packages\home-ui\bug.js
  5:13  error  'maxItems' PropType is defined but prop is never used                react/no-unused-prop-types
  6:27  error  'itemOpacityOutputRange' PropType is defined but prop is never used  react/no-unused-prop-types

  7:27  error  'textOpacityOutputRange' PropType is defined but prop is never used  react/no-unused-prop-types

code:

// @flow
import * as React from 'react';

type Props = {
  maxItems: number,
  itemOpacityOutputRange: Array<number>,
  textOpacityOutputRange: Array<number>,
  itemScaleOutputRange: Array<number>,
  children: Object => React.Node,
};

type State = {
  foo: number,
  bar: number,
};

function computeStateFromProps(props: Props) {
  const { maxItems, itemOpacityOutputRange, textOpacityOutputRange, itemScaleOutputRange } = props;

  if (maxItems && itemOpacityOutputRange && textOpacityOutputRange && itemScaleOutputRange) {
    return { foo: 0, bar: 0 };
  }
  return { foo: 1, bar: 0 };
}

export default class X extends React.PureComponent<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = computeStateFromProps(props);
  }

  animateItem = (index: ?number) => {
    const { itemScaleOutputRange } = this.props;
    if (itemScaleOutputRange && index) return 0;
    return 1;
  };

  render() {
    const {
      animateItem,
      props: { children },
    } = this;

    return <>{children({ animateItem })}</>;
  }
}

@matthargett The rule only considered props.foo as used if it is used directly inside the component. Passing the props to a function and use props.foo will not work. You can work around it by doing:

this.state = computeStateFromProps({
  maxItems: props.maxItems,
  itemOpacityOutputRange: props.itemOpacityOutputRange,
  ...
})

Passing the props or state object around is a massive antipattern; always extract the props you need directly, and then pass them separately, or as a new object, to other functions.

Was this page helpful?
0 / 5 - 0 ratings