ANimator120
ANimator120

Reputation: 3421

Component definition is missing display name for forwardRef

I was following this tutorial on using React.forwardRef, where make this component:

import React from "react";

const Search = React.forwardRef<HTMLInputElement>((props, ref) => {
  return <input ref={ref} type="search" />;
});

export default Search;

However, running my app, the component causes the following error:

Component definition is missing display name  react/display-name

Based on this question, I thought I might do something like this:

const Search = MySearch = React.forwardRef<HTMLInputElement>((props, ref) => {
  return <input ref={ref} type="search" />;
});

export default Search;

But this did not fix the problem either.

So then, how can I give my component a display name?

Upvotes: 125

Views: 92035

Answers (10)

DinhNguyen
DinhNguyen

Reputation: 945

Base on A. Backhagen 's answer, add a few edits to work with typescript:

const ComponentName = (props, ref: React.ForwardedRef< HTMLInputElement >) => {
  return (
    <div ref={ref}></div>
  );
};
export const ExportName = forwardRef(ComponentName);

Upvotes: 0

Here is my solution the previous ones didnt work for me:

import React, { forwardRef, Ref } from 'react';
import { SliderItemContainer, SliderItemContent } from '../styles/SliderItem.styles';
import { SliderItemType } from '../utils/Slider.data';

type SliderItemProps = {
  item: SliderItemType;
};

const SliderItem = ({ item }: SliderItemProps, ref: Ref<HTMLDivElement>) => {
  return (
    <SliderItemContainer ref={ref} image={item.image}>
      <SliderItemContent>
        <h1>{item.title}</h1>
        <p>{item.description}</p>
        <button>{item.buttonText}</button>
      </SliderItemContent>
    </SliderItemContainer>
  );
};

export default forwardRef(SliderItem);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Usage outside of the component is also simple I just wrapped SliderItem component with motion, named it MotionSliderItem.

const MotionSliderItem = motion(SliderItem);
<MotionSliderItem ..... />

Upvotes: 2

Sergey P. aka azure
Sergey P. aka azure

Reputation: 4742

You could use a named function (see function Search) instead of the anonymous arrow fn, like in the example below.

const Search = React.forwardRef<HTMLInputElement>(function Search(props, ref) {
  return <input ref={ref} type="search" />;
});

export default Search;

Upvotes: 49

Mr Washington
Mr Washington

Reputation: 1413

All the answers here using types, here is our solution with interfaces:

import { Ref, forwardRef } from 'react';

interface Props {
    "foo": string
}

const Input = ({ foo }: Props, ref: Ref<HTMLInputElement>) => {
    return <input foo={foo} ref={ref} type="text" />;
};

export default forwardRef(Input);

Upvotes: 0

Gamote
Gamote

Reputation: 803

In addition to Larsson's response (which I think it's the way to go), if you still want to have the typings you can do something like this:

import { forwardRef, ForwardRefRenderFunction } from "react";

type MyComponentProps = {
  something: string;
}

type RefProps = {
  something: string;
}

const MyComponent: ForwardRefRenderFunction<RefProps, MyComponentProps> = (props, ref) => {
  return <div>Works</div>;
}

export default forwardRef(MyComponent);

Upvotes: 20

A. Backhagen
A. Backhagen

Reputation: 1407

I've recently had the same issue and resolved it this way. Might not be the prettiest but could be preferred to some. Where ComponentName is the React name and the ExportName is what you will import in other places.

const ComponentName = (props, ref) => {
  return (
    <div ref={ref}></div>
  );
};
export const ExportName = forwardRef(ComponentName);

Upvotes: 55

Lukas Thiersch
Lukas Thiersch

Reputation: 165

I had a similar issue today. I use the DetailsList from @fluentui: Each column has an optional property onRender which passes the current item so that you can return a custom component to format your data. I was trying something like this: onRender: (item: PlannerTask) => <TitleColumn item={item} />. This gave me the error. I found two ways to fix it for me.

Varian 1: Give the child a name

onRender: function titleColumn (item: PlannerTask) { return <TitleColumn item={item} /> }

Variant 2 (what I did eventually):

In my component file I also export a function that returns the component:

export const createTitleColumn = (item: PlannerTask): JSX.Element => {
    return <TitleColumn item={item} />
}

Then I just pass this:

onRender: createTitleColumn

Conclusion

I like this variant most because it doesn't overcomplicate things and I personally found the second option to be very readable as well.

Overall I think that the eslint error was a false positive in my case, because there's nothing wrong with my original code. However I try to avoid disabling linting or compiler errors/rules, because they don't just exist to annoy us ;)

Upvotes: 0

Zhu Ziggs
Zhu Ziggs

Reputation: 181

import React from "react";

const Search = React.forwardRef<HTMLInputElement>(function Search(props, ref) {
  return <input ref={ref} type="search" />;
});

export default Search;

In this way, you can fix the problem. I suggest we'd better know why eslint limit the way of writting

Upvotes: 18

Frost
Frost

Reputation: 11977

The Component definition is missing display name react/display-name message is likely coming from a tool like eslint.

It is a linting rule that exists in order to help you follow style guides and/or conventions regarding what is considered good practice when writing React code.

That particular rule in eslint is explained in further details here: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md

From that page you can also find why it exists and what the displayName property on React Components is good for, namely to help when debugging, since it means that it will print your component's displayName property to the console instead of just input.

Also, from that link, you can find that when you are using function components, you can address that by setting the displayName property on the component. This should probably help you:

import React from "react";

const Search = React.forwardRef<HTMLInputElement>((props, ref) => {
  return <input ref={ref} type="search" />;
});
Search.displayName = "Search";

export default Search;

Another option is to just disable that particular linter, using a comment with // eslint-disable-next-line react/display-name or similar just above the declaration of your component.

That would however mean that if you were to need to debug your app, this component would simply be called input instead of Search, which might make the debugging a bit harder.

Upvotes: 256

Shivam
Shivam

Reputation: 1424

Put this at the beginning of your file:

/* eslint-disable react/display-name */

You could also try this: // eslint-disable-next-line react/display-name

Upvotes: -1

Related Questions