Avoid anonymous components with `displayName`
The React dev tools are great and you should use them, they'll make your life as a React dev easier, trust me.
The components tab of the React devtools displays the tree of components (with their names).
You can search for a component and view the values of its props and state, even other hooks too.
For me, the React dev tools have largely supplanted the need to console.log
in components.
Though there's nothing wrong with using console.log
, or the debugger if that's more your thing.
Anyway, there are two exceptions where the devtools are unable to infer a name of a component.
Contexts and 'wrapped' or 'higher-order' components, for example components wrapped in memo
and forwardRef
.
The devtools need some help to be able to display a name for those, this is where the displayName
property comes in.
By default, the devtools will show Context.Provider
for every context.
Context
objects have a displayName
property that you can set to a helpful name and React will use it in debugging messages.
The React DevTools will also use it to display a name (big surprise),
It's useful because it makes it easier to see what's what in the React dev tools when dealing with multiple nested context providers.
I certainly recommend setting it for contexts in library code to .
I set this for each and every Context
object I create, I should really make an ESLint rule for it 🤔.


Pyramids of Context.Providers
are a common sight in React, whether you
should be making these is another question. Consistently setting Context.displayName
at
least makes it easy to see which is which.
Context.displayName
for a useSafeContext
hook
It's to use a custom provider and consumer hook instead of useContext()
directly.
For one, a custom consumer hook is named (like useSomething
) which clearly emphasizes its intent. And second, it can throw an error with a helpful warning when it's used outside the provider.
Just read this post by Kent C Dodds: How to use React Context effectively.
Or this one Why I always wrap Context.Provider and useContext by Vladimir Klepov.
One practical application of Context.displayName
is making a generic consumer hook for contexts.
To build on Kent's example:
const CountContext = React.createContext();
CountContext.displayName = "CountContext";
// custom consumer hook
function useSafeContext(contextObject) {
const context = React.useContext(contextObject);
if (!contextObject.displayName) {
throw new Error(
"Context.displayName is not set, it must be set for useSafeContext"
);
}
if (context === undefined) {
// Get the displayName without "Context", so just "Count" here
const contextName = contextObject.displayName.split("Context")[0];
throw new TypeError(`use${contextName} must be used within a ${contextName}Provider`);
// "useCount must be used within a CountProvider"
}
return context;
}
// named hook
function useCount() {
const context = useSafeContext(CountContext);
return context;
}
React.memo()
and React.forwardRef()
are both utilities that wrap components,
In case you haven't heard of them, I'll leave it to the docs to explain what they do exactly.
Components wrapped in memo()
or forwardRef()
are commonly written as inline anonymous functions, like this:
const HeavyComponent = React.memo((props) => (
<div>{/* Big expensive component tree here */}</div>
));
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
At least, this is how I write them.
The thing is that this way memoed components will appear as Anonymous memo in the React dev tools because React can't infer a name from them, which makes them hard to find.
For function components, React uses Function.name
(I'm pretty sure) to get a display name.
Anonymous functions, by definition, lack a name, so React resorts to the "Anonymous" fallback.
Likewise, forwardRef
’d components written like this will show as Anonymous with a ForwardRef badge, which is equally unhelpful 1.
There are a few different ways to solve this. You can either:
- Use a named function declaration with the same name for the wrapped function. This can lead to shadowing, which you or your ESlint config may not like.
const HeavyComponent = React.memo(
function HeavyComponent(props) { ... }
)
- Reassign the function. Same story, some folks think it looks weird and there’s a rule in the default recommend ESLint config that complains about it.
function HeavyComponent(props) {
...
}
HeavyComponent = React.memo(HeavyComponent)
- Give the unmemoized component a different name. The devtools will display the name of the unmemoized component, in this case
UnmemoizedHeavyComponent
memo, which doesn't feel right to me.
function UnmemoizedHeavyComponent(props) { ... }
const HeavyComponent = React.memo(UnmemoizedHeavyComponent)
- All this hassle is exactly why memoed and forwardReffed components also have a
displayName
property. We get to have it all by writing an anonymous function and settingdisplayName
.
const HeavyComponent = React.memo(() => (props) { ... })
HeavyComponent.displayName = "HeavyComponent"
eslint-pugin-react/display-name
There's a somewhat dated eslint-plugin-react rule to ensure each component has a displayName
.
Just from the examples on the rules page you can tell it’s dated, createReactClass
is from before my time. It does show the case for memoed component but I don't think I've ever turned this rule on.
displayName
is also a property on class components, it's not that useful as React infers it from the class name, it's only for overriding the inferred name.
On top of that I haven't written a class component in a long time.
-
↩
ForwardRef: Displaying a custom name in DevToolsReact.forwardRef
accepts a render function. React DevTools uses this function to determine what to display for the ref forwarding component. For example, the following component will appear as ”ForwardRef” in the DevTools -
↩
@types/react NamedExoticComponenttypescript interface NamedExoticComponent<P = {}> extends ExoticComponent<P> { displayName?: string | undefined; }