-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Named hooks #323
Comments
One thing that The problem is that This could potentially break with strange setups like the |
This is really well thought-out! I think my issue with the I believe adding an -arity argument to the original react provided hooks to name them, and then a Then docs can reference: const [count, setCount] = React.useState(0, { name: 'count' }); and people will catch on that the name is for debugging purposes in the DevTools. |
For custom hooks it will naturally build a stack:
|
After some more thought, if we did have a |
This repository is being merged into the main React repo (github.com/facebook/react). As part of this, I am moving all issues to that repository as well and closing them here. This issue has been relocated to: |
This issue has been relocated to: facebook/react#16474
The problem
One common piece of feedback about DevTools hooks integration is that hooks have no name and can be confusing. Consider the following example:
Currently in DevTools the above component would be displayed as follows:
This information isn't as rich as we would prefer.☹️
The next question is often: "can you use the name of the variable the hook return value is assigned to?" but this is tricky because DevTools doesn't actually have any way to access that variable. (Even if DevTools has a handle on the
Example
function above, how would it access theuseSomeCustomHook
function?)The proposal
The solution to this would be some form of user-defined metadata (preferably generated by a code transform). Building on the precedent of the
useDebugValue
hook (facebook/react#14559), we might introduce a new no-op hook e.g.useDebugName
.The above example could make use of this hook like so:
DevTools could then display something like:
Implementation details
The new
useDebugName
hook might be a noop hook provided by React (similar touseDebugValue
) or it could even be an export from the (soon to be releasedreact-debug-hooks
package). The key concerns would be that:DevTools could override the no-op
useDebugName
implementation before inspecting a component and automatically associate the provided name with the most recently called native hook.For example, the following code should only result in one named hook (the second
useState
call).Being able to support sparse name metadata would be important for third party code (that might not be transformed to supply the metadata).
A code transform would be ideal for this scenario because manual annotation would probably be cumbersome. This could also be marketed as a DEV-only transform so as not to bloat production bundles with display names. We might even try to detect the env and throw if it isn't DEV (like facebook/react#15939).
Further considerations
Custom hooks?
In some cases, custom hooks might also be ambiguous. Consider the
useSubscription
hook (facebook/react#15022):Currently in DevTools the above component would be displayed as follows:
Maybe the value alone (provided by
useDebugValue
) could be enough to uniquely identify the hook, but I suspect in many cases it might not be sufficient. Should we then useuseDebugName
for custom hooks as well?I think it would be more fragile given the way our custom hooks detection logic is implemented. Custom hooks are not identified until after a component has finished rendering. In order for us to associate names with custom hooks, we would need to maintain a stack of names. This could lead to potential mismatches though in the event that
useDebugName
was called more (or fewer) times than there are custom hooks.For example, consider the following code:
The proposed implementation of
useDebugName
would be robust enough to handle naming "foo" and "baz" states and leaving "bar" as anonymous state hook. If we were maintaining a stack of names however, this discrepency would be more difficult to manage.Perhaps there is a clever solution to this problem. I would probably suggest leaving it out of the initial implementation though and only revisiting if we determine it's a necessary feature.
Alternatives considered
Pass debug name as an additional (unused) parameter
An alternative approach to calling a separate hook for naming purposes would be to pass the display name as an additional parameter to the native hook, e.g.:
Pros:
Cons:
useReducer
has optional parameters that the transform (or manual code) would need to be aware of to avoid a runtime error.Load source code (with source maps) and parse for name
We could use an extension API like
Resource.getContent
to load the source code (including custom hooks) and parse it determine the hook/variable names. Essentially this would work like the proposed transform above, but at runtime.Pros:
Cons:
Call
toString
on the function component and parse for nameA possible 80/20 variant of the above proposal would be to simply call
toString
on the function component and parse any top-level hooks.Pros:
Cons:
Use a Babel transform to leave an inline comment (and call
toString
to search for it)Rather than inserting a call to a new custom hook, our code transform could just insert an inline comment with the name. We could then parse the code to find the inline comment, e.g.:
Pros:
Cons:
The text was updated successfully, but these errors were encountered: