@samitouri / QOS-React-2 / commits / 96f7646a1a

Updated hydration logic to handle custom objects

Brian Vaughn committed Jun 12, 2019 at 15:43 UTC 96f7646a1a0acf0555632ce00e57522b54b1c91e
5 files changed +102 -6
shells/dev/app/InspectableElements/CustomObject.js new
+18
@@ -0,0 +1,18 @@
1 +// @flow
2 +
3 +import React from 'react';
4 +
5 +class Custom {
6 + _number = 42;
7 + get number() {
8 + return this._number;
9 + }
10 +}
11 +
12 +export default function CustomObject() {
13 + return <ChildComponent customObject={new Custom()} />;
14 +}
15 +
16 +function ChildComponent(props: any) {
17 + return null;
18 +}
shells/dev/app/InspectableElements/InspectableElements.js
+2
@@ -3,6 +3,7 @@
3 import React, { Fragment } from 'react';
4 import Contexts from './Contexts';
5 import CustomHooks from './CustomHooks';
6 +import CustomObject from './CustomObject';
7 import NestedProps from './NestedProps';
8
9 // TODO Add Immutable JS example
@@ -14,6 +15,7 @@ export default function InspectableElements() {
15 <NestedProps />
16 <Contexts />
17 <CustomHooks />
18 + <CustomObject />
19 </Fragment>
20 );
21 }
src/__tests__/__snapshots__/inspectedElementContext-test.js.snap
+22
@@ -114,3 +114,25 @@ exports[`InspectedElementContext should poll for updates for the currently selec
114 "state": null
115 }
116 `;
117 +
118 +exports[`InspectedElementContext should support custom objects with enumerable properties and getters: 1: mount 1`] = `
119 +[root]
120 + <Example>
121 +`;
122 +
123 +exports[`InspectedElementContext should support custom objects with enumerable properties and getters: 2: Inspected element 2 1`] = `
124 +{
125 + "id": 2,
126 + "owners": null,
127 + "context": null,
128 + "events": null,
129 + "hooks": null,
130 + "props": {
131 + "data": {
132 + "_number": 42,
133 + "number": 42
134 + }
135 + },
136 + "state": null
137 +}
138 +`;
src/__tests__/inspectedElementContext-test.js
+59
@@ -257,4 +257,63 @@ describe('InspectedElementContext', () => {
257
258 done();
259 });
260 +
261 + it('should support custom objects with enumerable properties and getters', async done => {
262 + class CustomData {
263 + _number = 42;
264 + get number() {
265 + return this._number;
266 + }
267 + set number(value) {
268 + this._number = value;
269 + }
270 + }
271 +
272 + const descriptor = ((Object.getOwnPropertyDescriptor(
273 + CustomData.prototype,
274 + 'number'
275 + ): any): PropertyDescriptor<number>);
276 + descriptor.enumerable = true;
277 + Object.defineProperty(CustomData.prototype, 'number', descriptor);
278 +
279 + const Example = ({ data }) => null;
280 +
281 + const container = document.createElement('div');
282 + await utils.actAsync(() =>
283 + ReactDOM.render(<Example data={new CustomData()} />, container)
284 + );
285 + expect(store).toMatchSnapshot('1: mount');
286 +
287 + const example = ((store.getElementAtIndex(0): any): Element);
288 +
289 + let didFinish = false;
290 +
291 + function Suspender({ target }) {
292 + const { read } = React.useContext(InspectedElementContext);
293 + const inspectedElement = read(target.id);
294 + expect(inspectedElement).toMatchSnapshot(
295 + `2: Inspected element ${target.id}`
296 + );
297 + didFinish = true;
298 + return null;
299 + }
300 +
301 + await utils.actAsync(
302 + () =>
303 + TestRenderer.create(
304 + <Contexts
305 + defaultSelectedElementID={example.id}
306 + defaultSelectedElementIndex={0}
307 + >
308 + <React.Suspense fallback={null}>
309 + <Suspender target={example} />
310 + </React.Suspense>
311 + </Contexts>
312 + ),
313 + false
314 + );
315 + expect(didFinish).toBe(true);
316 +
317 + done();
318 + });
319 });
src/hydration.js
+1 -6
@@ -194,12 +194,7 @@ export function dehydrate(
194 },
195 };
196 case 'object':
197 - if (
198 - level > LEVEL_THRESHOLD ||
199 - (data.constructor &&
200 - typeof data.constructor === 'function' &&
201 - data.constructor.name !== 'Object')
202 - ) {
197 + if (level > LEVEL_THRESHOLD) {
198 return createDehydrated(type, data, cleaned, path);
199 } else {
200 const res = {};