eslint-plugin-react: [react/require-default-props] False positive with React.forwardRef

The react/require-default-props rule configured with ignoreFunctionalComponents: true produces false positives for functional components that use React.forwardRef, like the following:

import React from "react"
import PropTypes from "prop-types"

const Demo = React.forwardRef((props, ref) => {
  const { text } = props
  return <div ref={ref}>{text}</div>
})

Demo.propTypes = {
  // Error: propType "text" is not required, but has no corresponding defaultProps declaration
  text: PropTypes.string,
}

export default Demo

Here are two CodeSandbox links demonstrating the problem with both .jsx and .tsx files:

Run yarn lint to reproduce.

I would expect components built with React.forwardRef to be considered functional components and be ignored when ignoreFunctionalComponents is true.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 9
  • Comments: 22 (7 by maintainers)

Most upvoted comments

Hi, I have a similar case.

I’m using "react/require-default-props": ["error", { functions: "defaultArguments" }] and I have a component similar to this

import React, {  forwardRef, memo } from 'react';
import PropTypes from 'prop-types';

const Button = forwardRef(({
  children,
  onClick = () => { console.log('Button clicked') },
}, ref) => (
  <button
    type="button"
    onClick={onClick}
    ref={ref}
  >
    {content}
  </button>
));

Button.propTypes = {
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func,
};

export default memo(Button);

What I expected here is to not have Eslint errors since we are specifying default props in the function arguments as is configured. However, react eslint plugin is not detecting this as a function component because of the forwardRef and enforces me to define Button.defaultProps.

Can this be solved?

Indeed, forwardRef does not take a component - in that case, that’s just a normal function.

However, in this case, the warning is 100% correct. You provided a non-required propType, without a defaultProp. The point of the rule is to error on that.

Note that functional components accept propTypes, defaultProps, contextTypes, etc - almost every static property that class components support, functional components do.

HI @chandra-logituit. Yes, they are the only workarounds I know to face the issue with the false positives when using forwardRef.

Hi @chandra-logituit. You have two options:

  • define defaultProps as the component was a Class component (i.e. using MyComponent.defaultProps):
import React, {  forwardRef, memo } from 'react';
import PropTypes from 'prop-types';

const Button = forwardRef(({
  children,
  onClick,
}, ref) => (
  <button
    type="button"
    onClick={onClick}
    ref={ref}
  >
    {content}
  </button>
));

Button.defaultProps = {
  onClick: () => { console.log('Button clicked') },
};

Button.propTypes = {
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func,
};

export default memo(Button);

or,

  • define the component as a function and wrap it in forwardRef in a different clause (ugly)
import React, {  forwardRef, memo } from 'react';
import PropTypes from 'prop-types';

const Button =({
  children,
  onClick = () => { console.log('Button clicked') },
}, ref) => (
  <button
    type="button"
    onClick={onClick}
    ref={ref}
  >
    {content}
  </button>
);

Button.propTypes = {
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func,
};

export default memo(forwardRef(Button));