Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using forwardRef with proptypes and eslint

I am trying to use forwardRef for a Button in a project using eslint and prop-types.

This is what I tried so far, and the errors I get each time:

First attempt

function Button ({ action = { callback: () => {}, title: 'unknown' } }, ref) {
  return (<button ref={ref} onClick={action.callback} title={action.description} type="button">{action.icon || action.title}</button>)
}

Button.propTypes = {
  action: Action.isRequired
}

export default forwardRef(Button)

This will give me the following warning in the console: Warning: forwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?

Second attempt

function ButtonFunction ({ action = { callback: () => {}, title: 'unknown' } }, ref) {
  return (<button ref={ref} onClick={action.callback} title={action.description} type="button">{action.icon || action.title}</button>)
}

const Button = forwardRef(ButtonFunction);

Button.propTypes = {
  action: Action.isRequired
}

export default ButtonFunction;

I get: action is missing in props validation.

Third attempt

const Button = forwardRef(({ action = { callback: () => {}, title: 'unknown' } }, ref) => {
  return (<button ref={ref} onClick={action.callback} title={action.description} type="button">{action.icon || action.title}</button>)
});

Button.propTypes = {
  action: Action.isRequired
}

export default Button;

This time, I get: Component definition is missing display name.

So what is the correct way to do this?

like image 229
Sharcoux Avatar asked Jan 13 '20 11:01

Sharcoux


3 Answers

You are almost done with your third attempt. But you don't have to use twice forwardRef, the first use with the Button declaration is enough. The display name rule is not an error (neither at JavaScript nor React level), but rather an intentional prop in order to show the "real" name of the component, used by React in debugging messages. In your case, the forwardRef function will hide the "real" component name for the transpiler.

You can even disable this rule if it's a real problem to write displayName for each of those case.

https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md

const Button = forwardRef(({ action = { callback: () => {}, title: 'unknown' } }, ref) => {
  return (<button ref={ref} onClick={action.callback} title={action.description} type="button">{action.icon || action.title}</button>)
});

Button.propTypes = {
  action: Action.isRequired
}

Button.displayName = 'Button'

export default Button
like image 164
MadDeveloper Avatar answered Nov 11 '22 19:11

MadDeveloper


const Form = React.forwardRef(function Form(
  { submitHandler, keyUpHandler, label, type, placeholder, buttonTxt },
  ref
) {

export default Form

No warnings doing this way. function Form takes care of the name.

like image 6
CodeFinity Avatar answered Nov 11 '22 19:11

CodeFinity


interface SomeProps {
 // written your props
};

const SomeFC = forwardRef((props:SomeProps,ref)=>{
// do something and returns
}})

Declare the type of props for inner FC can fix the proptypes warnning!

like image 2
ahaya Avatar answered Nov 11 '22 19:11

ahaya