react: Bug: Native Component Stacks don't respect function "displayName" in Firefox
Edit See this comment for the key part of what’s being reported/discussed on this issue: https://github.com/facebook/react/issues/22315#issuecomment-920061727
Original bug report below
As of #18561 component stacks are generated from native stack frames. This is problematic with HOCs that inherit from the input component in order to change its behavior. The somewhat popular @risingstack/react-easy-state package is one example of such a component. While it does assign a displayName, the new Native Component Stacks appear to ignore this. Instead, components wrapped in view() (from react-easy-state) are always shown with the name of the wrapper class, i.e., ReactiveComp or ReactiveClassComp.
This is especially catastrophic in the case of react-easy-state, where one is supposed to wrap essentially all components in the entire codebase in the view() HOC. The result is that component stacks become unusable for debugging.
Is there perhaps a way to work around this (e.g. disable native component stacks, or some new way to explicitly provide a component name like displayName)?
React version: 17.0.1
Steps To Reproduce
- Apply a HOC that uses inheritance (i.e., inherits from the component instead of wrapping it in JSX) to a component.
- The component will always be named
ReactiveComporReactiveClassCompin component stack traces.
Link to code example: https://codesandbox.io/s/rough-tdd-wqepe?file=/src/App.tsx
The current behavior
Something went wrong.
Error: sorry
BadGuy@https://7ww9j.csb.app/src/App.tsx:21:9
ErrorBoundary@https://7ww9j.csb.app/src/App.tsx:33:5
div
App
Something went wrong.
Error: sorry
ReactiveComp@https://7ww9j.csb.app/node_modules/@risingstack/react-easy-state/dist/es.es6.js:62:53
ErrorBoundary@https://7ww9j.csb.app/src/App.tsx:33:5
div
App
Note how the component wrapped in view() is shown as ReactiveComp instead of either the function name or the explicitly assigned displayName.
The expected behavior
The name of the ReactiveComp wrapper should never appear in component stacks.
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 19 (8 by maintainers)
Looks like this issue has been inactive for awhile - if you’d prefer I open a new issue, let me know.
The following issue still exists:
From reading the underlying React Source code, this behavior appears to be intentional, with the idea being native component stacks will give you the most accurate information for debugging. I agree with this to a point, but as noted earlier in the thread, this is very problematic for Higher Order Components which want to preserve the name of the component they’re wrapping.
In fact, this is such a primary use case that it is covered specifically in the React docs: https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging
As it stands currently, that documentation is not accurate, because defining
displayNamedoesn’t do anything.This is all independent of alternate mechanisms such as the previously mentioned
definePropertyhack. Regardless of whether this hack works or not, the lack of support fordisplayNameshould be considered a bug, in my opinion, until the documentation is updated and/or a new convention is provided for how to make higher order components debuggable.Accordingly, I would at least petition to drop “in Firefox” from this issue title, as the
displayNameissue is browser independent - it is only the workaround hack that is related to Firefox.My personal suggestion is to override a portion of the stack frame with the
displayNameif it is set. This would require only a slight alteration to the code introduced by PR #22477 mentioned above, by adding the followingelse ifclause:I am not certain if this is robust enough for general use, but it solved the problem for me and is at least a step in the right direction.
Given the age of this issue, it seems like it won’t be fixed any time soon. However, I did find a workaround!
To recap, the problem is that given a snippet like this:
the closure will simply be named
wrappedComponentand so the original name of the wrapped component (wrapped.name) is lost. While the most convenient solution here would undoubtedly be if React had a way to just override that name, we have to assume for now that this feature is not coming back.So we need a way to set the actual name (and not just a shadowed “name” property like the hack for Chrome) of our closure to whatever
wrapped.namesays. It seems impossible - after all, the closure is named by the variable, and variable names are source code literals. So we can’t just create a variable with a dynamic name, can we? In fact, we can do just that:Also works for class components:
Implemented in react-easy-state here: https://github.com/RisingStack/react-easy-state/commit/458e4bb8b9367a082f80d9ce15a45d58b06c7333
You can
Object.definePropertyinstead forname. This works: https://codesandbox.io/s/tender-easley-vck0q?file=/src/App.tsxOkay! Glad we’re on the same page. 😃
I’m on-call for DevTools this week so I don’t really have the bandwidth to dig in any further, but I think we have enough info now for this to be discussed/decided.
I’m not positive but I don’t think what you’re looking for is possible (reading the
displayNamefor the “native stack”) because we useErrorto construct these stacks (so they’ll be in the exact same format) andErrordoesn’t care about thedisplayNameconvention.