React DevTools and Unknown Components

June 09, 2018 0 Comments

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>
); }
}

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>
); }
}

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>
); }
}

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>
); }
}

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>
); }
}

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>
); }
}

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


Tag cloud