Skip to content

Commit bb9f556

Browse files
authored
Add React 18 support (#111)
* Bump deps to 18 * Add React 18 support * Don't assume stack format
1 parent 8ebe478 commit bb9f556

5 files changed

+106
-19
lines changed

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"homepage": "https://reactjs.org/",
1717
"dependencies": {
1818
"object-assign": "^4.1.1",
19-
"react-is": "^16.12.0 || ^17.0.0"
19+
"react-is": "^16.12.0 || ^17.0.0 || ^18.0.0"
2020
},
2121
"devDependencies": {
2222
"@babel/cli": "^7.8.4",
@@ -45,14 +45,14 @@
4545
"jest-diff": "^25.1.0",
4646
"lint-staged": "^10.0.8",
4747
"prettier": "1.19.1",
48-
"react": "^16.12.0",
48+
"react": "^18.0.0",
4949
"rimraf": "^3.0.1",
5050
"rollup": "^1.30.1",
5151
"rollup-plugin-babel": "^4.3.3",
5252
"rollup-plugin-strip-banner": "^1.0.0"
5353
},
5454
"peerDependencies": {
55-
"react": "^16.0.0 || ^17.0.0"
55+
"react": "^16.0.0 || ^17.0.0 || ^18.0.0"
5656
},
5757
"files": [
5858
"LICENSE",

src/ReactShallowRenderer.js

+17-2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ class ReactShallowRenderer {
169169
this._didScheduleRenderPhaseUpdate = false;
170170
this._renderPhaseUpdates = null;
171171
this._numberOfReRenders = 0;
172+
this._idCounter = 0;
172173
}
173174

174175
_validateCurrentlyRenderingComponent() {
@@ -311,7 +312,6 @@ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix th
311312
responder,
312313
});
313314

314-
// TODO: implement if we decide to keep the shallow renderer
315315
const useTransition = config => {
316316
this._validateCurrentlyRenderingComponent();
317317
const startTransition = callback => {
@@ -320,12 +320,22 @@ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix th
320320
return [startTransition, false];
321321
};
322322

323-
// TODO: implement if we decide to keep the shallow renderer
324323
const useDeferredValue = (value, config) => {
325324
this._validateCurrentlyRenderingComponent();
326325
return value;
327326
};
328327

328+
const useId = () => {
329+
this._validateCurrentlyRenderingComponent();
330+
const nextId = ++this._idCounter;
331+
return ':r' + nextId + ':';
332+
};
333+
334+
const useSyncExternalStore = (subscribe, getSnapshot) => {
335+
this._validateCurrentlyRenderingComponent();
336+
return getSnapshot();
337+
};
338+
329339
return {
330340
readContext,
331341
useCallback: identity,
@@ -337,13 +347,16 @@ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix th
337347
useEffect: noOp,
338348
useImperativeHandle: noOp,
339349
useLayoutEffect: noOp,
350+
useInsertionEffect: noOp,
340351
useMemo,
341352
useReducer,
342353
useRef,
343354
useState,
344355
useResponder,
356+
useId,
345357
useTransition,
346358
useDeferredValue,
359+
useSyncExternalStore,
347360
};
348361
}
349362

@@ -437,11 +450,13 @@ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix th
437450
// Start over from the beginning of the list
438451
this._workInProgressHook = null;
439452
this._rendering = false;
453+
this._idCounter = 0;
440454
this.render(element, context);
441455
} else {
442456
this._workInProgressHook = null;
443457
this._renderPhaseUpdates = null;
444458
this._numberOfReRenders = 0;
459+
this._idCounter = 0;
445460
}
446461
}
447462

src/__tests__/ReactShallowRenderer-test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1210,8 +1210,8 @@ describe('ReactShallowRenderer', () => {
12101210
shallowRenderer.render(React.createElement(SimpleComponent, {name: 123})),
12111211
).toErrorDev(
12121212
'Warning: Failed prop type: Invalid prop `name` of type `number` ' +
1213-
'supplied to `SimpleComponent`, expected `string`.\n' +
1214-
' in SimpleComponent',
1213+
'supplied to `SimpleComponent`, expected `string`.',
1214+
{withoutStack: true},
12151215
);
12161216
});
12171217

src/__tests__/ReactShallowRendererHooks-test.js

+75-1
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,12 @@ describe('ReactShallowRenderer with hooks', () => {
233233
effectsCalled.push('useEffect');
234234
});
235235

236+
React.useInsertionEffect(() => {
237+
effectsCalled.push('useInsertionEffect');
238+
});
239+
236240
React.useLayoutEffect(() => {
237-
effectsCalled.push('useEffect');
241+
effectsCalled.push('useLayoutEffect');
238242
});
239243

240244
return <div>Hello world</div>;
@@ -482,4 +486,74 @@ describe('ReactShallowRenderer with hooks', () => {
482486
result = shallowRenderer.render(element);
483487
expect(result).toEqual(5);
484488
});
489+
490+
it('should work with useId', () => {
491+
function SomeComponent({defaultName}) {
492+
const id = React.useId();
493+
const id2 = React.useId();
494+
495+
return (
496+
<div>
497+
<div id={id} />
498+
<div id={id2} />
499+
</div>
500+
);
501+
}
502+
503+
const shallowRenderer = createRenderer();
504+
let result = shallowRenderer.render(<SomeComponent />);
505+
506+
expect(result).toEqual(
507+
<div>
508+
<div id=":r1:" />
509+
<div id=":r2:" />
510+
</div>,
511+
);
512+
513+
result = shallowRenderer.render(<SomeComponent />);
514+
515+
expect(result).toEqual(
516+
<div>
517+
<div id=":r1:" />
518+
<div id=":r2:" />
519+
</div>,
520+
);
521+
});
522+
523+
it('should work with useSyncExternalStore', () => {
524+
function createExternalStore(initialState) {
525+
const listeners = new Set();
526+
let currentState = initialState;
527+
return {
528+
set(text) {
529+
currentState = text;
530+
listeners.forEach(listener => listener());
531+
},
532+
subscribe(listener) {
533+
listeners.add(listener);
534+
return () => listeners.delete(listener);
535+
},
536+
getState() {
537+
return currentState;
538+
},
539+
getSubscriberCount() {
540+
return listeners.size;
541+
},
542+
};
543+
}
544+
545+
const store = createExternalStore('hello');
546+
547+
function SomeComponent() {
548+
const value = React.useSyncExternalStore(store.subscribe, store.getState);
549+
return <div>{value}</div>;
550+
}
551+
552+
const shallowRenderer = createRenderer();
553+
let result = shallowRenderer.render(<SomeComponent />);
554+
expect(result).toEqual(<div>hello</div>);
555+
store.set('goodbye');
556+
result = shallowRenderer.render(<SomeComponent />);
557+
expect(result).toEqual(<div>goodbye</div>);
558+
});
485559
});

yarn.lock

+9-11
Original file line numberDiff line numberDiff line change
@@ -4488,7 +4488,7 @@ prompts@^2.0.1:
44884488
kleur "^3.0.3"
44894489
sisteransi "^1.0.4"
44904490

4491-
prop-types@^15.6.2, prop-types@^15.7.2:
4491+
prop-types@^15.7.2:
44924492
version "15.7.2"
44934493
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
44944494
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -4525,19 +4525,17 @@ react-is@^16.12.0, react-is@^16.8.1:
45254525
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
45264526
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
45274527

4528-
"react-is@^16.12.0 || ^17.0.0":
4529-
version "17.0.0"
4530-
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.0.tgz#7d6ec2a5c3de3ae2c0bfa7586305115ec1192110"
4531-
integrity sha512-6IY5dc12jn4xU1kM25NVb86Zn472Kq70jcS7qpdQiSVPyng+7dnFH7BxHLX/Fwm2PZF6OJNEoHx6Zgivt/dZ+A==
4528+
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0":
4529+
version "18.0.0"
4530+
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.0.0.tgz#026f6c4a27dbe33bf4a35655b9e1327c4e55e3f5"
4531+
integrity sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==
45324532

4533-
react@^16.12.0:
4534-
version "16.14.0"
4535-
resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
4536-
integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
4533+
react@^18.0.0:
4534+
version "18.0.0"
4535+
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
4536+
integrity sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==
45374537
dependencies:
45384538
loose-envify "^1.1.0"
4539-
object-assign "^4.1.1"
4540-
prop-types "^15.6.2"
45414539

45424540
read-pkg-up@^7.0.1:
45434541
version "7.0.1"

0 commit comments

Comments
 (0)