Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Support useDebugValueLabel() hook
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Vaughn committed Jan 10, 2019
1 parent 46f69d9 commit b5ac442
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 22 deletions.
34 changes: 33 additions & 1 deletion backend/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
Dispatcher.useImperativeMethods(undefined, () => null);
Dispatcher.useCallback(() => {});
Dispatcher.useMemo(() => null);
Dispatcher.useDebugValueLabel(null);
} finally {
readHookLog = hookLog;
hookLog = [];
Expand Down Expand Up @@ -194,6 +195,14 @@ function useCallback<T>(callback: T, inputs: Array<mixed> | void | null): T {
return callback;
}

function useDebugValueLabel(valueLabel: any) {
hookLog.push({
primitive: 'DebugValueLabel',
stackError: new Error(),
value: valueLabel,
});
}

function useMemo<T>(
nextCreate: () => T,
inputs: Array<mixed> | void | null,
Expand All @@ -210,6 +219,7 @@ const Dispatcher = {
useContext,
useEffect,
useImperativeMethods,
useDebugValueLabel,
useLayoutEffect,
useMemo,
useReducer,
Expand Down Expand Up @@ -396,7 +406,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
const children = [];
levelChildren.push({
name: parseCustomHookName(stack[j - 1].functionName),
value: undefined, // TODO: Support custom inspectable values.
value: undefined,
subHooks: children,
});
stackOfChildren.push(levelChildren);
Expand All @@ -410,9 +420,31 @@ function buildTree(rootStack, readHookLog): HooksTree {
subHooks: [],
});
}

// Associate custom hook values (useInpect() hook entries) with the correct hooks
rootChildren.forEach(hooksNode => rollupDebugValueLabels(hooksNode));

return rootChildren;
}

function rollupDebugValueLabels(hooksNode: HooksNode): void {
const useInpectHooksNodes: Array<HooksNode> = [];
hooksNode.subHooks = hooksNode.subHooks.filter(subHooksNode => {
if (subHooksNode.name === 'DebugValueLabel') {
useInpectHooksNodes.push(subHooksNode);
return false;
} else {
rollupDebugValueLabels(subHooksNode);
return true;
}
});
if (useInpectHooksNodes.length === 1) {
hooksNode.value = useInpectHooksNodes[0].value;
} else if (useInpectHooksNodes.length > 1) {
hooksNode.value = useInpectHooksNodes.map(({value}) => value);
}
}

export function inspectHooks<Props>(
currentDispatcher: ReactCurrentDispatcher,
renderFunction: Props => React$Node,
Expand Down
1 change: 1 addition & 0 deletions frontend/HooksTreeView.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
}

.nameCustom {
color: var(--theme-special03);
margin: 0 0.25rem;
cursor: pointer;
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/HooksTreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function HooksNodeView({ hooksNode, index, inspect, path, theme }: HooksNodeView

<div className={isCustomHook ? styles.nameCustom : styles.name}>
{name}:
</div> {!isCustomHook && <div className={styles.value}>{preview}</div>}
</div> {<div className={styles.value}>{preview}</div>}
</div>

{hasBeenHydrated && isOpen &&
Expand Down
49 changes: 29 additions & 20 deletions test/example/target.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,34 @@ ThemeContext.displayName = 'ThemeContext';

const LocaleContext = React.createContext('en-US');

const {useCallback, useEffect, useState} = React;
const {useCallback, useDebugValueLabel, useEffect, useState} = React;

// Below copied from https://usehooks.com/
function useTheme(theme) {
function useDebounce(value, delay) {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);

// Show the value in DevTools
useDebugValueLabel(debouncedValue);

useEffect(
() => {
for (var key in theme) {
document.documentElement.style.setProperty(`--${key}`, theme[key]);
}
// Update debounced value after delay
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);

// Cancel the timeout if value changes (also on delay change or unmount)
// This is how we prevent debounced value from updating if value is changed ...
// .. within the delay period. Timeout gets cleared and restarted.
return () => {
clearTimeout(handler);
};
},
[theme]
[value, delay] // Only re-call effect if value or delay changes
);

return debouncedValue;
}
// Above copied from https://usehooks.com/

Expand All @@ -62,11 +78,6 @@ function useNestedOuterHook() {
return useNestedInnerHook();
}

const cssVars = {
'background-color': 'green',
color: 'white',
};

const hooksTestProps = {
string: 'abc',
number: 123,
Expand All @@ -78,20 +89,18 @@ const hooksTestProps = {

function FunctionWithHooks(props, ref) {
const [count, updateCount] = useState(0);
const onClick = useCallback(() => updateCount(count + 1), [count]);

useNestedOuterHook();
// Custom hook with a custom debug label
const debouncedCount = useDebounce(count, 1000);

useTheme(cssVars);
const onClick = useCallback(() => updateCount(count + 1), [count]);

const style = {
backgroundColor: 'var(--background-color)',
color: 'var(--color)',
};
// Tests nested custom hooks
useNestedOuterHook();

return (
<button style={style} onClick={onClick}>
Count: {count}
<button onClick={onClick}>
Count: {debouncedCount}
</button>
);
}
Expand Down

0 comments on commit b5ac442

Please sign in to comment.