Updated hydration logic to handle custom objects

This commit is contained in:
Brian Vaughn 2019-06-12 15:43:15 -07:00
parent cb10c3d6da
commit 96f7646a1a
5 changed files with 102 additions and 6 deletions

View File

@ -0,0 +1,18 @@
// @flow
import React from 'react';
class Custom {
_number = 42;
get number() {
return this._number;
}
}
export default function CustomObject() {
return <ChildComponent customObject={new Custom()} />;
}
function ChildComponent(props: any) {
return null;
}

View File

@ -3,6 +3,7 @@
import React, { Fragment } from 'react';
import Contexts from './Contexts';
import CustomHooks from './CustomHooks';
import CustomObject from './CustomObject';
import NestedProps from './NestedProps';
// TODO Add Immutable JS example
@ -14,6 +15,7 @@ export default function InspectableElements() {
<NestedProps />
<Contexts />
<CustomHooks />
<CustomObject />
</Fragment>
);
}

View File

@ -114,3 +114,25 @@ exports[`InspectedElementContext should poll for updates for the currently selec
"state": null
}
`;
exports[`InspectedElementContext should support custom objects with enumerable properties and getters: 1: mount 1`] = `
[root]
<Example>
`;
exports[`InspectedElementContext should support custom objects with enumerable properties and getters: 2: Inspected element 2 1`] = `
{
"id": 2,
"owners": null,
"context": null,
"events": null,
"hooks": null,
"props": {
"data": {
"_number": 42,
"number": 42
}
},
"state": null
}
`;

View File

@ -257,4 +257,63 @@ describe('InspectedElementContext', () => {
done();
});
it('should support custom objects with enumerable properties and getters', async done => {
class CustomData {
_number = 42;
get number() {
return this._number;
}
set number(value) {
this._number = value;
}
}
const descriptor = ((Object.getOwnPropertyDescriptor(
CustomData.prototype,
'number'
): any): PropertyDescriptor<number>);
descriptor.enumerable = true;
Object.defineProperty(CustomData.prototype, 'number', descriptor);
const Example = ({ data }) => null;
const container = document.createElement('div');
await utils.actAsync(() =>
ReactDOM.render(<Example data={new CustomData()} />, container)
);
expect(store).toMatchSnapshot('1: mount');
const example = ((store.getElementAtIndex(0): any): Element);
let didFinish = false;
function Suspender({ target }) {
const { read } = React.useContext(InspectedElementContext);
const inspectedElement = read(target.id);
expect(inspectedElement).toMatchSnapshot(
`2: Inspected element ${target.id}`
);
didFinish = true;
return null;
}
await utils.actAsync(
() =>
TestRenderer.create(
<Contexts
defaultSelectedElementID={example.id}
defaultSelectedElementIndex={0}
>
<React.Suspense fallback={null}>
<Suspender target={example} />
</React.Suspense>
</Contexts>
),
false
);
expect(didFinish).toBe(true);
done();
});
});

View File

@ -194,12 +194,7 @@ export function dehydrate(
},
};
case 'object':
if (
level > LEVEL_THRESHOLD ||
(data.constructor &&
typeof data.constructor === 'function' &&
data.constructor.name !== 'Object')
) {
if (level > LEVEL_THRESHOLD) {
return createDehydrated(type, data, cleaned, path);
} else {
const res = {};