Avoid Anonymous Components With the displayName Property
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 that, 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 1.
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 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 🤔. Update: I did! It’s now an option called checkContextObjects
in the eslint-plugin-react displayName
rule.


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
) 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:
_29const CountContext = React.createContext();_29CountContext.displayName = "CountContext";_29_29// custom consumer hook_29function useSafeContext(contextObject) {_29 const context = React.useContext(contextObject);_29_29 if (!contextObject.displayName) {_29 throw new Error(_29 "Context.displayName is not set, it must be set for useSafeContext"_29 );_29 }_29_29 if (context === undefined) {_29 // Get the displayName without "Context", so just "Count" here_29 const contextName = contextObject.displayName.split("Context")[0];_29 throw new TypeError(`use${contextName} must be used within a ${contextName}Provider`);_29 // "useCount must be used within a CountProvider"_29 }_29_29 return context;_29}_29_29// named hook_29function useCount() {_29 const context = useSafeContext(CountContext);_29_29 return context;_29}
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:
_10const HeavyComponent = React.memo((props) => (_10 <div>{/* Big expensive component tree here */}</div>_10));_10_10const FancyButton = React.forwardRef((props, ref) => (_10 <button ref={ref} className="FancyButton">_10 {props.children}_10 </button>_10));
At least, this is how I write them.
The thing is that this way memo
d 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 4.
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.
_10const HeavyComponent = React.memo(_10 function HeavyComponent(props) { ... }_10)
- 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.
_10function HeavyComponent(props) {_10 ..._10}_10HeavyComponent = 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.
_10function UnmemoizedHeavyComponent(props) { ... }_10_10const HeavyComponent = React.memo(UnmemoizedHeavyComponent)
- All this hassle is exactly why memoized and forwardReffed components also have a
displayName
property. We get to have it all by writing an anonymous function and settingdisplayName
.
_10const HeavyComponent = React.memo(() => (props) { ... })_10HeavyComponent.displayName = "HeavyComponent"
Keep it in mind and help yourself and your fellow devs next time writing Context, memoized or forwardReffed components!
There’s an ESLint rule in eslint-plugin-react to ensure each component has a displayName
and it can catch missing displayName
s on memo
and forwardRef
components.
I recommend you to enable it so you won’t forget.
-
↩The
React docs: React.Component `displayName`displayName
string is used in debugging messages. Usually, you don’t need to set it explicitly because it’s inferred from the name of the function or class that defines the component. You might want to set it explicitly if you want to display a different name for debugging purposes or when you create a higher-order component -
↩
React Docs: forwardRef - Parametersrender
: The render function for your component. React calls this function with the props andref
that your component received from its parent. The JSX you return will be the output of your component. -
↩
React forwardRef source codeforwardRef
requires a render function but received amemo
+ component. Instead offorwardRef(memo(...))
, usememo(forwardRef(...)).
-
↩
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; }
-
↩For the most boring take, let’s see what React itself considers a component, by looking at @types/react and the react-dom implementation. Actually, many things work: [...] An object returned from
Thoughtspile - What is a react component, anyways?React.memo
,forwardRef
,Context
and some other builtins [React.lazy
]. They are called exotic components and trigger special renderer behavior.