简体   繁体   中英

How to properly use forwardRef in Typescript?

I'm very new to React, please bear with me

I have a component

const Avatar = forwardRef((props, ref) => {
  const {
    color,
    className,
    size,
    tag: Tag,
    ...rest
  } = props

  return (
    <Tag
      className={classnames('avatar', {
        [className]: className,
        [`bg-${color}`]: color,
        [`avatar-${size}`]: size
      })}
      ref={ref}
      {...rest}
    >
      ... //rest of codes
    </Tag>
  )
})

export default Avatar

Now, I can do this in javascript

<Avatar size="sm" color="success" />

However, in Typescript I will be getting error message

Property 'size' does not exist on type 'IntrinsicAttributes & RefAttributes<any>'  

Any idea what went wrong? I assume I need to pass ref so I do

const ref = React.createRef<Tag>();
<Avatar ref={ref} size="sm" color="success" />  

But I still have same issue, how do I pass size and color as props? I tried looking for answer around the inte.net and SO but I can't seem to find a solution, any help will be appreciated.

putting forwardRef on the export solves TSLint errors

const Avatar = (props, ref) => {
const {
 color,
 className,
 size,
 tag: Tag,
 ...rest
} = props

return (
  <Tag
  className={classnames('avatar', {
    [className]: className,
    [`bg-${color}`]: color,
    [`avatar-${size}`]: size
  })}
  ref={ref}
  {...rest}
  >
  ... //rest of codes
  </Tag>
 )
}

export default forwardRef(Avatar)

I'm not sure if you really need to forward ref or not. I hope my answer would give you some way to solve your use case. I can see that you pass Tag as a prop and you use it as JSX tag which is invalid.

Bare with me this piece of JSX code is invalid

<Tag
  className={classnames('avatar', {
    [className]: className,
    [`bg-${color}`]: color,
    [`avatar-${size}`]: size
  })}
  ref={ref}
  {...rest}
>
  ... //rest of codes
</Tag>

because you pass Tag as prop you cannot use it as JSX tag. You can pass a JSX tag as props but the implementation is not that way. You should import that tag instead or If you really want to pass it as prop. you need to compose it on its parent component.

Like this

const ParentComponent: React.FC = () => (
  <Avatar
    // You have to compose it here

    tag={
      <Tag
      // className={classnames('avatar', {
      //   [className]: className,
      //   [`bg-${color}`]: color,
      //   [`avatar-${size}`]: size
      // })}
      // ref={ref}
      // {...rest}
      >
        ... //rest of codes
      </Tag>
    }
  />
);

export default ParentComponent;

You may also interact the demo in codesandbox so you may get more Idea of what I'm trying to say. Just click it here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM