Skip to content

Commit 1d0564b

Browse files
author
Brian Vaughn
committed
Add Agent support for older backends
Add message forwarding for older backend methods: overrideContext, overrideHookState, overrideProps, and overrideState These events forward to the new overrideValueAtPath method. We do this because React Native embeds the React DevTools backend, but cannot control which version of the frontend users use.
1 parent 46b33e6 commit 1d0564b

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed

packages/react-devtools-shared/src/__tests__/editing-test.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,39 @@ describe('editable props and state', () => {
162162
});
163163
});
164164

165+
it('should still support overriding props values with legacy backend methods', async () => {
166+
await mountTestApp();
167+
168+
function overrideProps(id, path, value) {
169+
const rendererID = utils.getRendererID();
170+
bridge.send('overrideProps', {
171+
id,
172+
path,
173+
rendererID,
174+
value,
175+
});
176+
jest.runOnlyPendingTimers();
177+
}
178+
179+
overrideProps(classID, ['object', 'nested'], 'updated');
180+
expect(committedClassProps).toStrictEqual({
181+
array: [1, 2, 3],
182+
object: {
183+
nested: 'updated',
184+
},
185+
shallow: 'initial',
186+
});
187+
188+
overrideProps(functionID, ['shallow'], 'updated');
189+
expect(committedFunctionProps).toStrictEqual({
190+
array: [1, 2, 3],
191+
object: {
192+
nested: 'initial',
193+
},
194+
shallow: 'updated',
195+
});
196+
});
197+
165198
it('should have editable paths', async () => {
166199
await mountTestApp();
167200

@@ -424,6 +457,28 @@ describe('editable props and state', () => {
424457
});
425458
});
426459

460+
it('should still support overriding state values with legacy backend methods', async () => {
461+
await mountTestApp();
462+
463+
function overrideState(path, value) {
464+
const rendererID = utils.getRendererID();
465+
bridge.send('overrideState', {
466+
id,
467+
path,
468+
rendererID,
469+
value,
470+
});
471+
jest.runOnlyPendingTimers();
472+
}
473+
474+
overrideState(['array', 1], 'updated');
475+
expect(committedState).toStrictEqual({
476+
array: [1, 'updated', 3],
477+
object: {nested: 'initial'},
478+
shallow: 'initial',
479+
});
480+
});
481+
427482
it('should have editable paths', async () => {
428483
await mountTestApp();
429484

@@ -623,6 +678,31 @@ describe('editable props and state', () => {
623678
});
624679
});
625680

681+
it('should still support overriding hooks values with legacy backend methods', async () => {
682+
await mountTestApp();
683+
684+
function overrideHookState(path, value) {
685+
const rendererID = utils.getRendererID();
686+
bridge.send('overrideHookState', {
687+
hookID,
688+
id,
689+
path,
690+
rendererID,
691+
value,
692+
});
693+
jest.runOnlyPendingTimers();
694+
}
695+
696+
overrideHookState(['shallow'], 'updated');
697+
expect(committedState).toStrictEqual({
698+
array: [1, 2, 3],
699+
object: {
700+
nested: 'initial',
701+
},
702+
shallow: 'updated',
703+
});
704+
});
705+
626706
it('should have editable paths', async () => {
627707
await mountTestApp();
628708

@@ -858,6 +938,35 @@ describe('editable props and state', () => {
858938
});
859939
});
860940

941+
it('should still support overriding context values with legacy backend methods', async () => {
942+
await mountTestApp();
943+
944+
function overrideContext(path, value) {
945+
const rendererID = utils.getRendererID();
946+
947+
// To simplify hydration and display of primitive context values (e.g. number, string)
948+
// the inspectElement() method wraps context in a {value: ...} object.
949+
path = ['value', ...path];
950+
951+
bridge.send('overrideContext', {
952+
id,
953+
path,
954+
rendererID,
955+
value,
956+
});
957+
jest.runOnlyPendingTimers();
958+
}
959+
960+
overrideContext(['object', 'nested'], 'updated');
961+
expect(committedContext).toStrictEqual({
962+
array: [1, 2, 3],
963+
object: {
964+
nested: 'updated',
965+
},
966+
shallow: 'initial',
967+
});
968+
});
969+
861970
it('should have editable paths', async () => {
862971
await mountTestApp();
863972

packages/react-devtools-shared/src/backend/agent.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,21 @@ type InspectElementParams = {|
7474
rendererID: number,
7575
|};
7676

77+
type OverrideHookParams = {|
78+
id: number,
79+
hookID: number,
80+
path: Array<string | number>,
81+
rendererID: number,
82+
value: any,
83+
|};
84+
85+
type SetInParams = {|
86+
id: number,
87+
path: Array<string | number>,
88+
rendererID: number,
89+
value: any,
90+
|};
91+
7792
type PathType = 'props' | 'hooks' | 'state' | 'context';
7893

7994
type DeletePathParams = {|
@@ -180,6 +195,14 @@ export default class Agent extends EventEmitter<{|
180195
bridge.addListener('viewAttributeSource', this.viewAttributeSource);
181196
bridge.addListener('viewElementSource', this.viewElementSource);
182197

198+
// Temporarily support newer standalone front-end to send commands to older backend.
199+
// We do this because React Native embeds the React DevTools backend,
200+
// but cannot control which version of the frontend users use.
201+
bridge.addListener('overrideContext', this.overrideContext);
202+
bridge.addListener('overrideHookState', this.overrideHookState);
203+
bridge.addListener('overrideProps', this.overrideProps);
204+
bridge.addListener('overrideState', this.overrideState);
205+
183206
if (this._isProfiling) {
184207
bridge.send('profilingStatus', true);
185208
}
@@ -338,6 +361,56 @@ export default class Agent extends EventEmitter<{|
338361
}
339362
};
340363

364+
// Temporarily support newer standalone front-end to send commands to older backend.
365+
overrideContext = ({id, path, rendererID, value}: SetInParams) => {
366+
this.overrideValueAtPath({
367+
id,
368+
path,
369+
rendererID,
370+
type: 'context',
371+
value,
372+
});
373+
};
374+
375+
// Temporarily support newer standalone front-end to send commands to older backend.
376+
overrideHookState = ({
377+
id,
378+
hookID,
379+
path,
380+
rendererID,
381+
value,
382+
}: OverrideHookParams) => {
383+
this.overrideValueAtPath({
384+
id,
385+
path,
386+
rendererID,
387+
type: 'hooks',
388+
value,
389+
});
390+
};
391+
392+
// Temporarily support newer standalone front-end to send commands to older backend.
393+
overrideProps = ({id, path, rendererID, value}: SetInParams) => {
394+
this.overrideValueAtPath({
395+
id,
396+
path,
397+
rendererID,
398+
type: 'props',
399+
value,
400+
});
401+
};
402+
403+
// Temporarily support newer standalone front-end to send commands to older backend.
404+
overrideState = ({id, path, rendererID, value}: SetInParams) => {
405+
this.overrideValueAtPath({
406+
id,
407+
path,
408+
rendererID,
409+
type: 'state',
410+
value,
411+
});
412+
};
413+
341414
reloadAndProfile = (recordChangeDescriptions: boolean) => {
342415
sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
343416
sessionStorageSetItem(

packages/react-devtools-shared/src/bridge.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ type HighlightElementInDOM = {|
3535
scrollIntoView: boolean,
3636
|};
3737

38+
type OverrideValue = {|
39+
...ElementAndRendererID,
40+
path: Array<string | number>,
41+
value: any,
42+
|};
43+
44+
type OverrideHookState = {|
45+
...OverrideValue,
46+
hookID: number,
47+
|};
48+
3849
type PathType = 'props' | 'hooks' | 'state' | 'context';
3950

4051
type DeletePath = {|
@@ -160,6 +171,14 @@ type FrontendEvents = {|
160171
NativeStyleEditor_measure: [ElementAndRendererID],
161172
NativeStyleEditor_renameAttribute: [NativeStyleEditor_RenameAttributeParams],
162173
NativeStyleEditor_setValue: [NativeStyleEditor_SetValueParams],
174+
175+
// Temporarily support newer standalone front-end to send commands to older backend.
176+
// We do this because React Native embeds the React DevTools backend,
177+
// but cannot control which version of the frontend users use.
178+
overrideContext: [OverrideValue],
179+
overrideHookState: [OverrideHookState],
180+
overrideProps: [OverrideValue],
181+
overrideState: [OverrideValue],
163182
|};
164183

165184
class Bridge<

0 commit comments

Comments
 (0)