From f60fa2cc9295c5656749b6153fb088098d9f8db2 Mon Sep 17 00:00:00 2001 From: ChenLei <2470828450@qq.com> Date: Tue, 19 Jan 2021 23:26:52 +0800 Subject: [PATCH] [devtools] Fix can't expand prop value in some scenario (#20534) Co-authored-by: Brian Vaughn --- .../src/__tests__/inspectedElement-test.js | 77 +++++++++++++++++++ .../__tests__/legacy/inspectElement-test.js | 60 +++++++++++++++ .../react-devtools-shared/src/hydration.js | 4 +- packages/react-devtools-shared/src/utils.js | 8 +- 4 files changed, 144 insertions(+), 5 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index 6a596a8b4a624..70a59b135e85e 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -1168,6 +1168,83 @@ describe('InspectedElement', () => { done(); }); + it('should allow component prop value and value`s prototype has same name params.', async done => { + const testData = Object.create( + { + a: undefined, + b: Infinity, + c: NaN, + d: 'normal', + }, + { + a: { + value: undefined, + writable: true, + enumerable: true, + configurable: true, + }, + b: { + value: Infinity, + writable: true, + enumerable: true, + configurable: true, + }, + c: { + value: NaN, + writable: true, + enumerable: true, + configurable: true, + }, + d: { + value: 'normal', + writable: true, + enumerable: true, + configurable: true, + }, + }, + ); + const Example = ({data}) => null; + const container = document.createElement('div'); + await utils.actAsync(() => + ReactDOM.render(, container), + ); + + const id = ((store.getElementIDAtIndex(0): any): number); + + let inspectedElement = null; + + function Suspender({target}) { + inspectedElement = useInspectedElement(target); + return null; + } + + await utils.actAsync( + () => + TestRenderer.create( + + + + + , + ), + false, + ); + expect(inspectedElement.props).toMatchInlineSnapshot(` + Object { + "data": Object { + "a": undefined, + "b": Infinity, + "c": NaN, + "d": "normal", + }, + } + `); + + done(); + }); + it('should not dehydrate nested values until explicitly requested', async done => { const Example = () => { const [state] = React.useState({ diff --git a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js index 05d2bdcbeb6eb..6d446ca481de9 100644 --- a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js @@ -588,6 +588,66 @@ describe('InspectedElementContext', () => { done(); }); + it('should allow component prop value and value`s prototype has same name params.', async done => { + const testData = Object.create( + { + a: undefined, + b: Infinity, + c: NaN, + d: 'normal', + }, + { + a: { + value: undefined, + writable: true, + enumerable: true, + configurable: true, + }, + b: { + value: Infinity, + writable: true, + enumerable: true, + configurable: true, + }, + c: { + value: NaN, + writable: true, + enumerable: true, + configurable: true, + }, + d: { + value: 'normal', + writable: true, + enumerable: true, + configurable: true, + }, + }, + ); + + const Example = ({data}) => null; + act(() => + ReactDOM.render( + , + document.createElement('div'), + ), + ); + + const id = ((store.getElementIDAtIndex(0): any): number); + const inspectedElement = await read(id); + + expect(inspectedElement.props).toMatchInlineSnapshot(` + Object { + "data": Object { + "a": undefined, + "b": Infinity, + "c": NaN, + "d": "normal", + }, + } + `); + done(); + }); + it('should not dehydrate nested values until explicitly requested', async done => { const Example = () => null; diff --git a/packages/react-devtools-shared/src/hydration.js b/packages/react-devtools-shared/src/hydration.js index 24379d675c4a9..69909cb2f658e 100644 --- a/packages/react-devtools-shared/src/hydration.js +++ b/packages/react-devtools-shared/src/hydration.js @@ -383,7 +383,9 @@ export function hydrate( const value = parent[last]; - if (value.type === 'infinity') { + if (!value) { + return; + } else if (value.type === 'infinity') { parent[last] = Infinity; } else if (value.type === 'nan') { parent[last] = NaN; diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index d84d5e67e98b6..be31af5c85ac8 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -70,8 +70,8 @@ export function alphaSortKeys( export function getAllEnumerableKeys( obj: Object, -): Array { - const keys = []; +): Set { + const keys = new Set(); let current = obj; while (current != null) { const currentKeys = [ @@ -82,7 +82,7 @@ export function getAllEnumerableKeys( currentKeys.forEach(key => { // $FlowFixMe: key can be a Symbol https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor if (descriptors[key].enumerable) { - keys.push(key); + keys.add(key); } }); current = Object.getPrototypeOf(current); @@ -767,7 +767,7 @@ export function formatDataForPreview( return data.toString(); case 'object': if (showFormattedValue) { - const keys = getAllEnumerableKeys(data).sort(alphaSortKeys); + const keys = Array.from(getAllEnumerableKeys(data)).sort(alphaSortKeys); let formatted = ''; for (let i = 0; i < keys.length; i++) {