question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Relying on function.name is brittle

See original GitHub issue

I think relying on fn.name makes the API very brittle. The function name can (and usually does!) change during minification.

I understand .dispayName or explicitly specifying it as a “fake name prop” works as a more reliable fallback but I don’t think most people will be aware unless you force this. The name prop is also problematic because components might accept a legitimate name prop, and the API clobbers it.

Apologies if I misunderstood the API!

(Note: I know it says in the README to set displayName. But most people won’t because it works without that in DEV.)

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:2
  • Comments:23 (8 by maintainers)

github_iconTop GitHub Comments

11reactions
gaearoncommented, Jan 31, 2018

Here’s a list of ways (2) counters my expectations:

  • Normally I can rename a component and all references to it, and things will work. However if I have a Heading in the same file as my usage of MediaObject, and then rename Heading to MyHeading, it breaks.

  • Normally I can rename the public API of a component, and updating callers alone is enough. However if I rename the Heading argument to MediaObject to MyHeading, I can’t pass the Heading component to it anymore.

These two issues are already very confusing to me. Imagine this function:

function power(x, y) {
  return x * y;
}

You can call it with any variables:

let a = 3;
let b = 5;
console.log(power(a, b));

The API in (2) is conceptually similar to enforcing that if x and y are ever renamed in power definition, local a and b in their callers must also be renamed, and vice versa. I find this to be a confusing limitation, especially in the context of JSX that normally works similar conceptually to function calls.

Even if x and y are named arguments you can still alias them:

let a = 3;
let b = 5;
console.log(
  power({x: a, y: b})
);

But here you can’t.

Let’s consider a specific example. Say both Heading and MediaObject come from npm. They work well together.

Then MediaObject 2.0 comes out, and it changes the “slot” to be called Header. If it was a prop you’d just pass a different prop:

- <MediaObject heading={<Heading />} />
+ <MediaObject header={<Heading />} />

Note this happens at the call site where you integrate both components. You don’t need to change their source.

However, with the approach in this library, this doesn’t actually work. We have to rename the argument now at its definition site:

- Heading.displayName = 'Heading';
+ Heading.displayName = 'Header';

What if you don’t have easy access to the Heading code? What if it’s unmaintained, or tricky to update? Well, you could do this:

function Header(props) {
  return <Heading {...props} />
}
Header.displayName = 'Header';

This component only exists so that MediaObject keeps working. Okay. Then somebody sees this code and thinks: unnecessary component indirection! Let’s remove it so that the code can run faster! They just change it to re-export Heading directly, and the code breaks again.

(In fact that’s exactly what a future React compiler might do. We’re working on folding React functional components at build time for better performance. So if code relies on displayName for correctness, it might actually not work with the future React optimizations.)

You get the same kind of problem if two “MediaObjects” maintained by different teams agree on slot naming at first but then one of them renames the slot and the other doesn’t. Now you have to wrap the component at least in one of the places.

9reactions
gaearoncommented, Jan 31, 2018

Here’s a pure React version of this pattern that doesn’t suffer from those drawbacks and in my subjective opinion it’s clearer what’s going on:

const MediaObject = ({
  image,
  heading,
  text
}) => (
  <Flex p={2} align='center'>
    <Box width={128}>
      {image}
    </Box>
    <Box>
      {heading}
      {text}
    </Box>
  </Flex>
))

const App = props => (
  <div>
    <MediaObject
      image={<Image src='kitten.png' />}
      heading={
        <Heading>
          Hello
        </Heading>      
      }
      text={
        <Text>
          This component keeps its tree structure but still allows for regular composition.
        </Text>      
      }
    />
  </div>
)

The input are explicit, there’s no reliance on names, it can be strongly typed, and there are no questions about how nesting works and whether you can reorder them: it’s just props.

(And it’s not a library, just React 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does the Airbnb style guide say that relying on function ...
Can someone please explain why "relying on function name inference is discouraged"? Is it just a style concern?
Read more >
"@jxnblk @mxstbr Relying on .name sounds very brittle. It ... - Twitter
Relying on .name sounds very brittle. It will be different after minification. ... I think relying on fn.name makes the API very brittle....
Read more >
Airbnb JavaScript Style Guide()
7.5 Never name a parameter arguments . This will take precedence over the arguments object that is given to every function scope. //...
Read more >
ECMAScript 6: arrow functions and method definitions - 2ality
Follow-up blog post from 2013-08-11: “Callable entities in ECMAScript 6”. In JavaScript, one aspect of creating a function inside a method ...
Read more >
4. Code Reuse: Functions and Modules - Head First Python ...
Python uses the name “function” to describe a reusable chunk of code. ... Depending on the programming languages you've used before, this may...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found