eslint-plugin-react: react/display-name false positive when wrapping inline function with React.memo

In 7.12.3, react/display-name gives a false positive if you wrap a function directly.

import React from 'react';

const Test = React.memo(props => (
  <div>{props.children}</div>
));
export default Test;

Related: (#2105 #2109)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 4
  • Comments: 15 (10 by maintainers)

Most upvoted comments

@ThiefMaster simple solution there, use a default export šŸ˜„

Haha, don’t worry, we also don’t use string selectors 😃 So yeah it sounds like the main reason not to use them is the sneakiness of not getting a name?

I just like keeping my eyes on ā€œbest practicesā€ 😃 Our situation here was we tried:

export const Foo = React.memo(() => <jsx />)

which violated eslint(react/display-name). We went with:

const NonMemoFoo = () => <jsx />
export const Foo = React.memo(NonMemoFoo)

before we saw this thread. So now our options seem to be:

// 1. What we have
const NonMemoFoo = () => <jsx />
export const Foo = React.memo(NonMemoFoo)

// 2. Manually set it
export const Foo = React.memo(() => <jsx />)
Foo.displayName = 'Foo'

// 3. 'One line' with named function syntax
export const Foo = React.memo(function Foo() { return <jsx /> })

// 4. Same as 1 except with function syntax
function NonMemoFoo() { return <jsx /> })
export const Foo = React.memo(NonMemoFoo)

is that right? Or is there another option I’m missing for exporting a memoized component with a display name? Would the preference be for the fourth option here?

unfortunately having to use a named function here is super ugly because it means i need to specify the function name twice when using a non-default export

const Foo = React.memo(function Foo() {
    return 'bar';
});
export {Foo};

for default exports i can do this to avoid it, and still have a proper name for the component (since it’s inferred automatically):

const Foo = function() {
    return 'bar';
};
export default React.memo(Foo);

simple solution there, use a default export šŸ˜„

In latest build, this appears to be broken for a default export (although… I’m in a typescript project, so this might be a problem specific to linting .tsx files):

export default React.memo(function LabelControl(props: ControlProps) {
    const control = props.control as OnDemandLabelControl;

    return (
        <ControlWrapper>
            <Translate tagName="h2" message={control.title} />
        </ControlWrapper>
    );
});

triggers react/display-name, but:

function LabelControl(props: ControlProps) {
    const control = props.control as OnDemandLabelControl;

    return (
        <ControlWrapper>
            <Translate tagName="h2" message={control.title} />
        </ControlWrapper>
    );
}

export default React.memo(LabelControl);

does not.

Indeed, in that case you have to store it in a variable first, or:

export default React.memo(Object.assign(function Foo() {
  return whatever;
}, {
  propTypes,
}));

You shouldn’t be using enzyme string selectors in any case 😃 debugging is harder without a name, and arrow functions only have a name via inference, which often will surprise you and not result in any name being inferred.

(You should allow default exports, but) export function Foo() {} works just fine and is what I’d recommend in that case.

If you use a named function instead of an arrow function (as is best practice for components, always) does the rule pass?

Yes, I would suggest 3 or 4. Note that 4 allows you to more easily put propTypes on the component directly, which you should always do (and which this plugin will warn you about also)