DEV Community

Cover image for React DevTools and Unknown Components
Kyle Blake
Kyle Blake

Posted on • Edited on

React DevTools and Unknown Components

I have been working with React for just about 2 years now, comprising about 95% of my professional work. Most issues are easy to find solutions to but one issue I see people have that does not seem to have a lot of documentation is cases of <Unknown> components when using React DevTools.

Generally speaking, React will infer the name of a component based on the function or class name provided. Most of the time, this is all you need to know and you shouldn't run in to any problems. However, there are a few ways to create React components that could lead to issues. I've put together some common examples and how they will appear in React DevTools.

I'll be using ES6 syntax throughout this post.

Class Components

Class components are pretty straight forward. I think most people tend to name their classes before exporting them.

// MyClassComp.js
class MyClassComp extends React.Component {
  render() {
    return <div> Hello World! </div>;
  };
}

export default MyClassComp;


// App.js
import MyClassComp from './MyClassComp';

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <MyClassComp />
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown1.png

No real surprise here, React can easily decipher the name of your component. What if we export the class directly?

// MyClassComp.js
export default class extends React.Component {
  render() {
    return <div> Hello World! </div>;
  };
}


// App.js
import MyClassComp from './MyClassComp';

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <MyClassComp />
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown2.png

Well, not quite an <Unknown> but still not very helpful information.

Functional Components

Functional components will generally work the same as class components. However, it is easier to create and export functional components in a variety of ways, so you have to be a bit more cognizant.

Here is an example of a named export and a default export.

// MyDefaultComp.js
export const MyNamedComp = props => <div> Named Export! </div>;

const MyDefaultComp = props => <div> Default Export! </div>;
export default MyDefaultComp;


// App.js
import MyDefaultComp, {MyNamedComp} from './MyDefaultComp';

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <MyNamedComp />
        <MyDefaultComp />
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown3.png

As you can see, both are named correctly in DevTools. But what if we were to export an anonymous function?

// MyFunctionalComp.js
export default props => <div> Hello World! </div>;


// App.js
import MyFunctionalComp from './MyFunctionalComp';

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <MyFunctionalComp />
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown4.png

I don't think it is much of a shock that DevTools now gives an <Unknown> component. We didn't provide a name to the component when exporting it so React can't infer it for us.

Higher-Order Components

Higher-order components are a bit more complicated. Here is higher-order that takes a component as an argument and renders it.

// HigherOrderComp.js
const HigherOrderComp = Wrapped => props => <Wrapped />;

export default HigherOrderComp;

// App.js
import HigherOrder from './HigherOrder';

const MyComponent = props => <div> Hello World! </div>;
const MyHOC = HigherOrder(MyComponent);

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <MyHOC />
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown5.png

Interesting! Despite defining a name for our higher-order component, the name gets lost in the DevTools. Also, the wrapped component retains its name!

Render Props

One last example of a more advanced technique using render props.

// RenderPropComp.js
class RenderPropComp extends React.Component {

  render() {
    const { Renderer } = this.props
    return <Renderer />;
  }
}

export default RenderPropComp;


// App.js
import TakesRenderer from './TakesRenderer';

const MyComponent = props => <div> Hello World! </div>;

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <TakesRenderer
          Renderer={MyComponent}
        />
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown6.png

Great, that preserves the names of both components!


The biggest take away is providing an explicit name when you define/export a React component can go a long way to making debugging easier. Personally, each component I create goes in a separate file, with a specific name, and an explicit export. In the case of composing components, I prefer the render props pattern over using higher-order components.

These are a few simple examples but I think they are worth considering. It can be very confusing looking through the React DevTools when it is a sea of <Unknown>. Considering these patterns could make your React debugging much easier.

Link and Further Reading

Top comments (3)

Collapse
 
dan_abramov profile image
Dan Abramov

To clarify some points.

No real surprise here, React can easily decipher the name of your component. What if we export the class directly?

The problem isn't with "exporting component directly". The problem is that you didn't give it a name.

Your code looks like this:

export default class extends React.Component {
  // ...
}

The class doesn't have a name. If you give it a name this won't be a problem (even though you still "export it directly"):

export default class MyComponent extends React.Component {
  // ...
}

Despite defining a name for our higher-order component, the name gets lost in the DevTools.

This isn't some problem inherent to HOCs themselves. The problem is in how HOC is defined. If it doesn't a class/function with a name... well, you know the rest. :-)

So you can totally write a HOC that adds a reasonable name, just follow the same suggestions you already wrote, but for the returned class itself.

Collapse
 
fargrim profile image
Kyle Blake

Dan,

Along with trying to help others, this post is just as much for me to see how well I understand a topic. I really appreciate that you took the time to read my post and offer up such helpful feedback because it not only improves the post, but it improves my knowledge on the topic.

I follow a lot of topics around React and Redux, so having you personally respond to this post blows my mind! Something I wouldn't have ever expected, so thank you again!

Collapse
 
johansedgeware profile image
Johan • Edited

How I write a HOC so that names are preserved in Devtools:

 export default WrapperComponent => function withWrapperComponent(props) {
     return (<WrapperComponent {...props} />)
 }

My HOC will now show up in Devtools like withWrapperComponent

We don't have to use anonymous functions all the time