Skip to content

Support configurable labels for custom hooks#14559

Merged
bvaughn merged 7 commits into
react:masterfrom
bvaughn:support-configurable-labels-for-custom-hooks
Jan 14, 2019
Merged

Support configurable labels for custom hooks#14559
bvaughn merged 7 commits into
react:masterfrom
bvaughn:support-configurable-labels-for-custom-hooks

Conversation

@bvaughn

@bvaughn bvaughn commented Jan 10, 2019

Copy link
Copy Markdown
Contributor

Builds on top of PR #14556 to add support for configurable labels for custom hooks (for DevTools) by way of a new, debug-only hook named useDebugValue.

Using the debounce hook from usehooks.com as an example:

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  // Show the debounced value inside of DevTools beside this hook:
  useDebugValue(debouncedValue);

  useEffect(
    () => {
      const handler = setTimeout(() => setDebouncedValue(value), delay);
      return () => clearTimeout(handler);
    },
    [value, delay]
  );

  return debouncedValue;
}

This would render like so:
screen shot 2019-01-09 at 9 51 25 pm

@sizebot

sizebot commented Jan 10, 2019

Copy link
Copy Markdown

ReactDOM: size: 0.0%, gzip: -0.0%

Details of bundled changes.

Comparing: f290138...fa8d3d1

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js 0.0% +0.1% 725.92 KB 726.15 KB 167.65 KB 167.75 KB UMD_DEV
react-dom.production.min.js 0.0% -0.0% 98.46 KB 98.46 KB 32.08 KB 32.08 KB UMD_PROD
react-dom.profiling.min.js 0.0% -0.0% 101.45 KB 101.45 KB 32.75 KB 32.75 KB UMD_PROFILING
react-dom.development.js 0.0% +0.1% 720.98 KB 721.21 KB 166.23 KB 166.32 KB NODE_DEV
react-dom.production.min.js 0.0% -0.0% 98.46 KB 98.46 KB 31.58 KB 31.58 KB NODE_PROD
react-dom.profiling.min.js 0.0% -0.0% 101.57 KB 101.57 KB 32.18 KB 32.18 KB NODE_PROFILING
ReactDOM-dev.js 0.0% +0.1% 742.27 KB 742.51 KB 167.24 KB 167.34 KB FB_WWW_DEV
ReactDOM-prod.js 0.0% 0.0% 308.82 KB 308.86 KB 57.07 KB 57.08 KB FB_WWW_PROD
ReactDOM-profiling.js 0.0% 0.0% 316.02 KB 316.05 KB 58.42 KB 58.43 KB FB_WWW_PROFILING
react-dom-unstable-fire.development.js 0.0% +0.1% 726.21 KB 726.44 KB 167.76 KB 167.86 KB UMD_DEV
react-dom-unstable-fire.production.min.js 0.0% -0.0% 98.48 KB 98.48 KB 32.09 KB 32.09 KB UMD_PROD
react-dom-unstable-fire.profiling.min.js 0.0% -0.0% 101.46 KB 101.46 KB 32.76 KB 32.76 KB UMD_PROFILING
react-dom-unstable-fire.development.js 0.0% +0.1% 721.26 KB 721.5 KB 166.34 KB 166.44 KB NODE_DEV
react-dom-unstable-fire.production.min.js 0.0% -0.0% 98.48 KB 98.48 KB 31.59 KB 31.59 KB NODE_PROD
react-dom-unstable-fire.profiling.min.js 0.0% -0.0% 101.58 KB 101.58 KB 32.19 KB 32.19 KB NODE_PROFILING
ReactFire-dev.js 0.0% +0.1% 741.42 KB 741.66 KB 167.16 KB 167.26 KB FB_WWW_DEV
ReactFire-prod.js 0.0% 0.0% 297.42 KB 297.45 KB 54.72 KB 54.73 KB FB_WWW_PROD
ReactFire-profiling.js 0.0% 0.0% 304.54 KB 304.57 KB 56.05 KB 56.07 KB FB_WWW_PROFILING
react-dom-test-utils.development.js 0.0% -0.0% 44.87 KB 44.87 KB 12.3 KB 12.3 KB UMD_DEV
react-dom-test-utils.production.min.js 0.0% -0.0% 9.97 KB 9.97 KB 3.71 KB 3.71 KB UMD_PROD
react-dom-test-utils.development.js 0.0% -0.0% 44.59 KB 44.59 KB 12.24 KB 12.24 KB NODE_DEV
react-dom-test-utils.production.min.js 0.0% -0.0% 9.74 KB 9.74 KB 3.65 KB 3.65 KB NODE_PROD
react-dom-unstable-native-dependencies.development.js 0.0% -0.0% 60.61 KB 60.61 KB 15.92 KB 15.92 KB UMD_DEV
react-dom-unstable-native-dependencies.development.js 0.0% -0.0% 60.29 KB 60.29 KB 15.79 KB 15.79 KB NODE_DEV
react-dom-unstable-native-dependencies.production.min.js 0.0% -0.0% 10.75 KB 10.75 KB 3.71 KB 3.71 KB NODE_PROD
react-dom-server.browser.development.js 0.0% -0.0% 123.9 KB 123.9 KB 33.09 KB 33.08 KB UMD_DEV
react-dom-server.browser.development.js 0.0% -0.0% 120.03 KB 120.03 KB 32.16 KB 32.16 KB NODE_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 16.87 KB 16.87 KB 6.51 KB 6.51 KB NODE_PROD
ReactDOMServer-dev.js 0.0% -0.0% 121.18 KB 121.18 KB 31.8 KB 31.8 KB FB_WWW_DEV
ReactDOMServer-prod.js 0.0% -0.0% 44.46 KB 44.46 KB 10.29 KB 10.29 KB FB_WWW_PROD
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.63 KB 3.63 KB 1.44 KB 1.44 KB UMD_DEV
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.1% 1.21 KB 1.21 KB 707 B 706 B UMD_PROD
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.45 KB 3.45 KB 1.39 KB 1.39 KB NODE_DEV
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.2% 1.05 KB 1.05 KB 637 B 636 B NODE_PROD
react-dom-unstable-fizz.node.development.js 0.0% -0.1% 3.7 KB 3.7 KB 1.42 KB 1.42 KB NODE_DEV
react-dom-unstable-fizz.node.production.min.js 0.0% -0.1% 1.1 KB 1.1 KB 668 B 667 B NODE_PROD

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js 0.0% +0.1% 506.32 KB 506.56 KB 111.61 KB 111.7 KB UMD_DEV
react-art.production.min.js 0.0% -0.0% 90.58 KB 90.58 KB 27.83 KB 27.83 KB UMD_PROD
react-art.development.js +0.1% +0.1% 437.82 KB 438.06 KB 94.48 KB 94.58 KB NODE_DEV
react-art.production.min.js 0.0% -0.0% 55.56 KB 55.56 KB 17.12 KB 17.12 KB NODE_PROD
ReactART-dev.js +0.1% +0.1% 445.95 KB 446.18 KB 93.47 KB 93.56 KB FB_WWW_DEV
ReactART-prod.js 0.0% 0.0% 184.91 KB 184.94 KB 31.63 KB 31.64 KB FB_WWW_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js 0.0% +0.1% 570.44 KB 570.67 KB 123.98 KB 124.08 KB RN_FB_DEV
ReactNativeRenderer-prod.js 0.0% 0.0% 240.46 KB 240.49 KB 42.29 KB 42.3 KB RN_FB_PROD
ReactNativeRenderer-profiling.js 0.0% 0.0% 246.63 KB 246.67 KB 43.68 KB 43.69 KB RN_FB_PROFILING
ReactNativeRenderer-dev.js 0.0% +0.1% 570.35 KB 570.59 KB 123.94 KB 124.03 KB RN_OSS_DEV
ReactNativeRenderer-profiling.js 0.0% -0.0% 231.83 KB 231.83 KB 40.7 KB 40.7 KB RN_OSS_PROFILING
ReactFabric-dev.js 0.0% +0.1% 561.29 KB 561.53 KB 121.67 KB 121.77 KB RN_FB_DEV
ReactFabric-prod.js 0.0% 0.0% 233.66 KB 233.69 KB 40.84 KB 40.85 KB RN_FB_PROD
ReactFabric-profiling.js 0.0% 0.0% 238.98 KB 239.02 KB 42.19 KB 42.2 KB RN_FB_PROFILING
ReactFabric-dev.js 0.0% +0.1% 561.2 KB 561.43 KB 121.63 KB 121.73 KB RN_OSS_DEV
ReactFabric-prod.js 0.0% -0.0% 219.01 KB 219.01 KB 37.83 KB 37.83 KB RN_OSS_PROD

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer.development.js +0.1% +0.1% 451.04 KB 451.27 KB 97.25 KB 97.35 KB UMD_DEV
react-test-renderer.production.min.js 0.0% -0.0% 56.96 KB 56.96 KB 17.51 KB 17.51 KB UMD_PROD
react-test-renderer.development.js +0.1% +0.1% 446 KB 446.23 KB 96.03 KB 96.13 KB NODE_DEV
react-test-renderer.production.min.js 0.0% -0.0% 56.63 KB 56.63 KB 17.35 KB 17.35 KB NODE_PROD
ReactTestRenderer-dev.js +0.1% +0.1% 454.34 KB 454.57 KB 95.36 KB 95.46 KB FB_WWW_DEV
react-test-renderer-shallow.development.js 0.0% -0.0% 25.67 KB 25.67 KB 6.95 KB 6.95 KB UMD_DEV
react-test-renderer-shallow.production.min.js 0.0% -0.0% 7.31 KB 7.31 KB 2.39 KB 2.38 KB UMD_PROD
react-test-renderer-shallow.production.min.js 0.0% -0.0% 7.96 KB 7.96 KB 2.64 KB 2.64 KB NODE_PROD

react-debug-tools

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-debug-tools.development.js +9.8% +9.6% 16.53 KB 18.15 KB 4.9 KB 5.38 KB NODE_DEV
react-debug-tools.production.min.js 🔺+7.6% 🔺+5.9% 5.16 KB 5.55 KB 2.14 KB 2.27 KB NODE_PROD

Generated by 🚫 dangerJS

@sebmarkbage

Copy link
Copy Markdown
Contributor

When I first saw the name “label” I thought it would be a string to name the field itself - which I don’t think we should do. But perhaps others could be confused by the name as I was.

How about useDebugValue?

Comment thread packages/react/src/ReactHooks.js Outdated

export function useDebugValueLabel(valueLabel: string) {
const dispatcher = resolveDispatcher();
return dispatcher.useDebugValueLabel(valueLabel);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we wrap this in if (__DEV__) {? That would make this function a noop which can be trivially eliminated by a bundler. At least with ES modules. So that would let us remove the callsite itself in prod bundles.

@Jessidhia

Jessidhia commented Jan 10, 2019 via email

Copy link
Copy Markdown
Contributor

@sebmarkbage

Copy link
Copy Markdown
Contributor

Not all dispatchers are noops so there still needs to be a lookup of which dispatcher is active and that thing called. A call is not a noop.

I.e. a bundler doesn’t know that it will be a noop so it can’t delete it. A VM can’t neither because any dispatcher can be installed that isn’t a noop.

@bvaughn

bvaughn commented Jan 10, 2019

Copy link
Copy Markdown
Contributor Author

Yeah, I dig useDebugValue. I just didn't like useInspect and wanted something that sounded more debuggy.

@bvaughn
bvaughn force-pushed the support-configurable-labels-for-custom-hooks branch from 5bf400e to 597af0f Compare January 10, 2019 16:05
Brian Vaughn added 4 commits January 10, 2019 08:25
1. Renamed useDebugValueLabel hook to useDebugValue
2. Wrapped useDebugValue internals in if-DEV so that it could be removed from production builds.
@bvaughn
bvaughn force-pushed the support-configurable-labels-for-custom-hooks branch from 597af0f to 5d7b4be Compare January 10, 2019 16:56
export function useDebugValue(valueLabel: string): void {
// This hook is normally a no-op.
// The react-debug-hooks package injects its own implementation
// so that e.g. DevTools can display customhook values.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "custom hooks"

});
}

// Associate custom hook values (useInpect() hook entries) with the correct hooks

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer called useInspect

return rootChildren;
}

function rollupDebugValues(hooksNode: HooksNode): void {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this function do exactly? I struggle to understand just from reading the code — maybe because of filter with a mutation and recursion inside. Not saying it needs to be changed but a brief comment about what it does to the tree would help.

]);
});

describe('useDebugValue', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also have a test for useDebugValue on top level of component? Outside a Hook.

@gaearon gaearon Jan 10, 2019

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also should we add tests for updates? To verify inspectHooksOfFiber can find latest version. (In case it matters — I don't understand this enough to tell yet.)

Ah nvm, I see you pass current fiber explicitly.

@bvaughn bvaughn Jan 10, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can add a test for that. I'm not sure what the expected behavior should be. A warning? Just ignore it entirely?

For now I'll just remove them.

@gaearon gaearon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how rollupDebugValues works but overall I think this makes sense.

@sebmarkbage sebmarkbage left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the transform function as second arg? Do we expect that we don't need that?

function rollupDebugValues(hooksNode: HooksNode): void {
let useInpectHooksNodes: Array<HooksNode> = [];
hooksNode.subHooks = hooksNode.subHooks.filter(subHooksNode => {
if (subHooksNode.name === 'DebugValue') {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should tag these nodes with something more unique to the built-in one so that it doesn't happen with custom hooks that happen to share the same name. E.g. You could also check that this is the terminal node. children.length === 0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I meant to do this but forgot. 😁

@bvaughn bvaughn Jan 10, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems trickier than I thought because of how we're parsing the stack for function names and then comparing them to the primitive labels.

For example, I can name the local function something more unique (e.g. useDebugValue__REACT_INTERNAL) but if it's assigned to the dispatcher as useDebugValue– then function name that's being parsed and passed to isReactWrapper is useDebugValue.

Maybe I'm overlooking something obvious. I'll come back to this.

Or maybe I'll just use the subHooks.length heuristic.


function rollupDebugValues(hooksNode: HooksNode): void {
let useInpectHooksNodes: Array<HooksNode> = [];
hooksNode.subHooks = hooksNode.subHooks.filter(subHooksNode => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just make this into a for-loop. Like Dan, I find it confusing if something is both functional style and imperative. I assume this to be pure if it's using filter.

@bvaughn

bvaughn commented Jan 10, 2019

Copy link
Copy Markdown
Contributor Author

What happened to the transform function as second arg? Do we expect that we don't need that?

I forgot about it 😄 I'll add it.

@bvaughn

bvaughn commented Jan 10, 2019

Copy link
Copy Markdown
Contributor Author

Okay, I think I've applied all of the suggested feedback.

1. Fixed some minor typos
2. Added inline comment explaining the purpose of  rollupDebugValues()
3. Refactored rollupDebugValues() to use a for loop rather than filter()
4. Improve check for useDebugValue hook to lessen the chance of a false positive
5. Added optional formatter function param to useDebugValue
@bvaughn
bvaughn force-pushed the support-configurable-labels-for-custom-hooks branch from 4a2d812 to 683907b Compare January 10, 2019 23:31
@bvaughn

bvaughn commented Jan 14, 2019

Copy link
Copy Markdown
Contributor Author

Ping! 😄 I guess dan already stamped this so nevermind

@bvaughn
bvaughn merged commit edb1f59 into react:master Jan 14, 2019
@bvaughn
bvaughn deleted the support-configurable-labels-for-custom-hooks branch January 14, 2019 22:53
@gaearon

gaearon commented Jan 15, 2019

Copy link
Copy Markdown
Collaborator

What about partial renderer (server), I don't see it in this PR? Should be a no-op too, otherwise it'll crash on use.

@bvaughn

bvaughn commented Jan 15, 2019

Copy link
Copy Markdown
Contributor Author

Rats. It's easy to forget about that use case. Thanks for the catch! 😄

I'll pick this up tomorrow with another PR!

Follow up PR: #14597

facebook-github-bot pushed a commit to facebook/flow that referenced this pull request Jan 22, 2019
Summary:
Add definitions for new debug hook, `useDebugValue` (react/react#14559)

I'm sorry for not updating tests 😦`make` and `yarn install` both still failing for me.

cc jbrown215
Pull Request resolved: #7356

Reviewed By: bvaughn

Differential Revision: D13672750

Pulled By: jbrown215

fbshipit-source-id: a48bd161f001ecfb770f9d708e762ffa3ed5b733
jetoneza pushed a commit to jetoneza/react that referenced this pull request Jan 23, 2019
* react-debug-tools accepts currentDispatcher ref as param

* ReactDebugHooks injected dispatcher ref is optional

* Support custom values for custom hooks

* PR feedback:

1. Renamed useDebugValueLabel hook to useDebugValue
2. Wrapped useDebugValue internals in if-DEV so that it could be removed from production builds.

* PR feedback:

1. Fixed some minor typos
2. Added inline comment explaining the purpose of  rollupDebugValues()
3. Refactored rollupDebugValues() to use a for loop rather than filter()
4. Improve check for useDebugValue hook to lessen the chance of a false positive
5. Added optional formatter function param to useDebugValue

* Nitpick renamed a method
n8schloss pushed a commit to n8schloss/react that referenced this pull request Jan 31, 2019
* react-debug-tools accepts currentDispatcher ref as param

* ReactDebugHooks injected dispatcher ref is optional

* Support custom values for custom hooks

* PR feedback:

1. Renamed useDebugValueLabel hook to useDebugValue
2. Wrapped useDebugValue internals in if-DEV so that it could be removed from production builds.

* PR feedback:

1. Fixed some minor typos
2. Added inline comment explaining the purpose of  rollupDebugValues()
3. Refactored rollupDebugValues() to use a for loop rather than filter()
4. Improve check for useDebugValue hook to lessen the chance of a false positive
5. Added optional formatter function param to useDebugValue

* Nitpick renamed a method
mrizwanashiq pushed a commit to mrizwanashiq/react that referenced this pull request Jun 25, 2026
* react-debug-tools accepts currentDispatcher ref as param

* ReactDebugHooks injected dispatcher ref is optional

* Support custom values for custom hooks

* PR feedback:

1. Renamed useDebugValueLabel hook to useDebugValue
2. Wrapped useDebugValue internals in if-DEV so that it could be removed from production builds.

* PR feedback:

1. Fixed some minor typos
2. Added inline comment explaining the purpose of  rollupDebugValues()
3. Refactored rollupDebugValues() to use a for loop rather than filter()
4. Improve check for useDebugValue hook to lessen the chance of a false positive
5. Added optional formatter function param to useDebugValue

* Nitpick renamed a method
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants