Skip to content

Commit 1a1bb85

Browse files
author
Brian Vaughn
committed
Added support for editable hook values (pending facebook/react/pull/14906)
1 parent 90f9837 commit 1a1bb85

File tree

13 files changed

+208
-48
lines changed

13 files changed

+208
-48
lines changed

shells/browser/shared/src/panels/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createElement } from 'react';
2-
import { createRoot, flushSync } from 'react-dom';
2+
import { unstable_createRoot as createRoot, flushSync } from 'react-dom';
33
import DevTools from 'src/devtools/views/DevTools';
44
import { getBrowserName, getBrowserTheme } from '../utils';
55

shells/dev/src/devtools.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { createElement } from 'react';
44
// $FlowFixMe Flow does not yet know about createRoot()
5-
import { createRoot } from 'react-dom';
5+
import { unstable_createRoot as createRoot } from 'react-dom';
66
import Bridge from 'src/bridge';
77
import { installHook } from 'src/hook';
88
import { initDevTools } from 'src/devtools';

src/backend/ReactDebugHooks.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ type ReactCurrentDispatcher = {
225225
};
226226

227227
type HooksNode = {
228+
nativeHookIndex: number,
228229
name: string,
229230
value: mixed,
230231
subHooks: Array<HooksNode>,
@@ -366,6 +367,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
366367
const rootChildren = [];
367368
let prevStack = null;
368369
let levelChildren = rootChildren;
370+
let nativeHookIndex = 0;
369371
const stackOfChildren = [];
370372
for (let i = 0; i < readHookLog.length; i++) {
371373
const hook = readHookLog[i];
@@ -399,6 +401,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
399401
levelChildren.push({
400402
name: parseCustomHookName(stack[j - 1].functionName),
401403
value: undefined,
404+
nativeHookIndex: -1,
402405
subHooks: children,
403406
});
404407
stackOfChildren.push(levelChildren);
@@ -409,12 +412,13 @@ function buildTree(rootStack, readHookLog): HooksTree {
409412
levelChildren.push({
410413
name: hook.primitive,
411414
value: hook.value,
415+
nativeHookIndex: hook.primitive === 'DebugValue' ? -1 : nativeHookIndex++,
412416
subHooks: [],
413417
});
414418
}
415419

416420
// Associate custom hook values (useDebugValue() hook entries) with the correct hooks.
417-
rollupDebugValues(rootChildren, null);
421+
processDebugValues(rootChildren, null);
418422

419423
return rootChildren;
420424
}
@@ -423,7 +427,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
423427
// That hook adds the user-provided values to the hooks tree.
424428
// This method removes those values (so they don't appear in DevTools),
425429
// and bubbles them up to the "value" attribute of their parent custom hook.
426-
function rollupDebugValues(
430+
function processDebugValues(
427431
hooksTree: HooksTree,
428432
parentHooksNode: HooksNode | null
429433
): void {
@@ -436,7 +440,7 @@ function rollupDebugValues(
436440
i--;
437441
debugValueHooksNodes.push(hooksNode);
438442
} else {
439-
rollupDebugValues(hooksNode.subHooks, hooksNode);
443+
processDebugValues(hooksNode.subHooks, hooksNode);
440444
}
441445
}
442446

src/backend/agent.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ type InspectSelectParams = {|
2323
rendererID: number,
2424
|};
2525

26+
type OverrideHookParams = {|
27+
id: number,
28+
nativeHookIndex: number,
29+
path: Array<string | number>,
30+
rendererID: number,
31+
value: any,
32+
|};
33+
2634
type SetInParams = {|
2735
id: number,
2836
path: Array<string | number>,
@@ -40,6 +48,7 @@ export default class Agent extends EventEmitter {
4048
bridge.addListener('highlightElementInDOM', this.highlightElementInDOM);
4149
bridge.addListener('inspectElement', this.inspectElement);
4250
bridge.addListener('overrideContext', this.overrideContext);
51+
bridge.addListener('overrideHook', this.overrideHook);
4352
bridge.addListener('overrideProps', this.overrideProps);
4453
bridge.addListener('overrideState', this.overrideState);
4554
bridge.addListener('selectElement', this.selectElement);
@@ -122,6 +131,21 @@ export default class Agent extends EventEmitter {
122131
}
123132
};
124133

134+
overrideHook = ({
135+
id,
136+
nativeHookIndex,
137+
path,
138+
rendererID,
139+
value,
140+
}: OverrideHookParams) => {
141+
const renderer = this._rendererInterfaces[rendererID];
142+
if (renderer == null) {
143+
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
144+
} else {
145+
renderer.setInHook(id, nativeHookIndex, path, value);
146+
}
147+
};
148+
125149
overrideProps = ({ id, path, rendererID, value }: SetInParams) => {
126150
const renderer = this._rendererInterfaces[rendererID];
127151
if (renderer == null) {

src/backend/index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
// @flow
22

3-
import type { Hook, ReactRenderer, RendererInterface } from './types';
3+
import type { DevToolsHook, ReactRenderer, RendererInterface } from './types';
44
import Agent from './agent';
55

66
import { attach } from './renderer';
77

8-
export function initBackend(hook: Hook, agent: Agent, global: Object): void {
8+
export function initBackend(
9+
hook: DevToolsHook,
10+
agent: Agent,
11+
global: Object
12+
): void {
913
const subs = [
1014
hook.sub(
1115
'renderer-attached',

src/backend/renderer.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import { getUID } from '../utils';
2424
import { inspectHooksOfFiber } from './ReactDebugHooks';
2525

2626
import type {
27+
DevToolsHook,
2728
Fiber,
28-
Hook,
2929
ReactRenderer,
3030
FiberData,
3131
RendererInterface,
@@ -151,7 +151,7 @@ function getInternalReactConstants(version) {
151151
}
152152

153153
export function attach(
154-
hook: Hook,
154+
hook: DevToolsHook,
155155
rendererID: number,
156156
renderer: ReactRenderer,
157157
global: Object
@@ -194,7 +194,7 @@ export function attach(
194194
DEPRECATED_PLACEHOLDER_SYMBOL_STRING,
195195
} = ReactSymbols;
196196

197-
const { overrideProps } = renderer;
197+
const { overrideHook, overrideProps } = renderer;
198198

199199
const debug = (name: string, fiber: Fiber, parentFiber: ?Fiber): void => {
200200
if (__DEBUG__) {
@@ -1141,7 +1141,10 @@ export function attach(
11411141
return {
11421142
id,
11431143

1144-
// Does the current renderer support editable props/state/hooks?
1144+
// Does the current renderer support editable hooks?
1145+
canEditHooks: typeof overrideHook === 'function',
1146+
1147+
// Does the current renderer support editable function props?
11451148
canEditFunctionProps: typeof overrideProps === 'function',
11461149

11471150
// Inspectable properties.
@@ -1163,6 +1166,20 @@ export function attach(
11631166
};
11641167
}
11651168

1169+
function setInHook(
1170+
id: number,
1171+
nativeHookIndex: number,
1172+
path: Array<string | number>,
1173+
value: any
1174+
) {
1175+
const fiber = findCurrentFiberUsingSlowPath(idToFiberMap.get(id));
1176+
if (fiber !== null) {
1177+
if (typeof overrideHook === 'function') {
1178+
overrideHook(fiber, nativeHookIndex, path, value);
1179+
}
1180+
}
1181+
}
1182+
11661183
function setInProps(id: number, path: Array<string | number>, value: any) {
11671184
const fiber = findCurrentFiberUsingSlowPath(idToFiberMap.get(id));
11681185
if (fiber !== null) {
@@ -1216,6 +1233,7 @@ export function attach(
12161233
cleanup,
12171234
renderer,
12181235
setInContext,
1236+
setInHook,
12191237
setInProps,
12201238
setInState,
12211239
walkTree,

src/backend/types.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ export type ReactRenderer = {
3333
findFiberByHostInstance: (hostInstance: NativeType) => ?Fiber,
3434
version: string,
3535
bundleType: BundleType,
36+
37+
// 16.9+
38+
overrideHook?: ?(
39+
fiber: Object,
40+
nativeHookIndex: number,
41+
path: Array<string | number>,
42+
value: any
43+
) => void,
44+
45+
// 16.7+
3646
overrideProps?: ?(
3747
fiber: Object,
3848
path: Array<string | number>,
@@ -55,15 +65,21 @@ export type RendererInterface = {
5565
inspectElement: (id: number) => InspectedElement | null,
5666
renderer: ReactRenderer | null,
5767
selectElement: (id: number) => void,
68+
setInContext: (id: number, path: Array<string | number>, value: any) => void,
69+
setInHook: (
70+
id: number,
71+
nativeHookIndex: number,
72+
path: Array<string | number>,
73+
value: any
74+
) => void,
5875
setInProps: (id: number, path: Array<string | number>, value: any) => void,
5976
setInState: (id: number, path: Array<string | number>, value: any) => void,
60-
setInContext: (id: number, path: Array<string | number>, value: any) => void,
6177
walkTree: () => void,
6278
};
6379

6480
export type Handler = (data: any) => void;
6581

66-
export type Hook = {
82+
export type DevToolsHook = {
6783
listeners: { [key: string]: Array<Handler> },
6884
rendererInterfaces: Map<RendererID, RendererInterface>,
6985
renderers: Map<RendererID, ReactRenderer>,
@@ -83,6 +99,7 @@ export type Hook = {
8399
};
84100

85101
export type HooksNode = {
102+
nativeHookIndex: number,
86103
name: string,
87104
value: mixed,
88105
subHooks: Array<HooksNode>,

src/devtools/types.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ export type Owner = {|
4848
export type InspectedElement = {|
4949
id: number,
5050

51+
// Does the current renderer support editable hooks?
52+
canEditHooks: boolean,
53+
5154
// Does the current renderer support editable function props?
5255
canEditFunctionProps: boolean,
5356

src/devtools/views/HooksTree.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,22 @@
33
border-top: 1px solid var(--color-border);
44
}
55

6-
.HooksNode {
6+
.Hook {
77
padding-left: 0.75rem;
88
}
99

1010
.NameValueRow {
11+
display: flex;
1112
}
1213

1314
.Name {
1415
color: var(--color-attribute-name);
16+
flex: 0 0 auto;
17+
}
18+
.Name:after {
19+
content: ': ';
20+
color: var(--color-text-color);
21+
margin-right: 0.5rem;
1522
}
1623

1724
.Value {

0 commit comments

Comments
 (0)