Skip to content

Commit

Permalink
Add React 18 support (#111)
Browse files Browse the repository at this point in the history
* Bump deps to 18

* Add React 18 support

* Don't assume stack format
  • Loading branch information
gaearon authored Apr 6, 2022
1 parent 8ebe478 commit bb9f556
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 19 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"homepage": "https://reactjs.org/",
"dependencies": {
"object-assign": "^4.1.1",
"react-is": "^16.12.0 || ^17.0.0"
"react-is": "^16.12.0 || ^17.0.0 || ^18.0.0"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
Expand Down Expand Up @@ -45,14 +45,14 @@
"jest-diff": "^25.1.0",
"lint-staged": "^10.0.8",
"prettier": "1.19.1",
"react": "^16.12.0",
"react": "^18.0.0",
"rimraf": "^3.0.1",
"rollup": "^1.30.1",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-strip-banner": "^1.0.0"
},
"peerDependencies": {
"react": "^16.0.0 || ^17.0.0"
"react": "^16.0.0 || ^17.0.0 || ^18.0.0"
},
"files": [
"LICENSE",
Expand Down
19 changes: 17 additions & 2 deletions src/ReactShallowRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ class ReactShallowRenderer {
this._didScheduleRenderPhaseUpdate = false;
this._renderPhaseUpdates = null;
this._numberOfReRenders = 0;
this._idCounter = 0;
}

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

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

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

const useId = () => {
this._validateCurrentlyRenderingComponent();
const nextId = ++this._idCounter;
return ':r' + nextId + ':';
};

const useSyncExternalStore = (subscribe, getSnapshot) => {
this._validateCurrentlyRenderingComponent();
return getSnapshot();
};

return {
readContext,
useCallback: identity,
Expand All @@ -337,13 +347,16 @@ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix th
useEffect: noOp,
useImperativeHandle: noOp,
useLayoutEffect: noOp,
useInsertionEffect: noOp,
useMemo,
useReducer,
useRef,
useState,
useResponder,
useId,
useTransition,
useDeferredValue,
useSyncExternalStore,
};
}

Expand Down Expand Up @@ -437,11 +450,13 @@ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix th
// Start over from the beginning of the list
this._workInProgressHook = null;
this._rendering = false;
this._idCounter = 0;
this.render(element, context);
} else {
this._workInProgressHook = null;
this._renderPhaseUpdates = null;
this._numberOfReRenders = 0;
this._idCounter = 0;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/ReactShallowRenderer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1210,8 +1210,8 @@ describe('ReactShallowRenderer', () => {
shallowRenderer.render(React.createElement(SimpleComponent, {name: 123})),
).toErrorDev(
'Warning: Failed prop type: Invalid prop `name` of type `number` ' +
'supplied to `SimpleComponent`, expected `string`.\n' +
' in SimpleComponent',
'supplied to `SimpleComponent`, expected `string`.',
{withoutStack: true},
);
});

Expand Down
76 changes: 75 additions & 1 deletion src/__tests__/ReactShallowRendererHooks-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,12 @@ describe('ReactShallowRenderer with hooks', () => {
effectsCalled.push('useEffect');
});

React.useInsertionEffect(() => {
effectsCalled.push('useInsertionEffect');
});

React.useLayoutEffect(() => {
effectsCalled.push('useEffect');
effectsCalled.push('useLayoutEffect');
});

return <div>Hello world</div>;
Expand Down Expand Up @@ -482,4 +486,74 @@ describe('ReactShallowRenderer with hooks', () => {
result = shallowRenderer.render(element);
expect(result).toEqual(5);
});

it('should work with useId', () => {
function SomeComponent({defaultName}) {
const id = React.useId();
const id2 = React.useId();

return (
<div>
<div id={id} />
<div id={id2} />
</div>
);
}

const shallowRenderer = createRenderer();
let result = shallowRenderer.render(<SomeComponent />);

expect(result).toEqual(
<div>
<div id=":r1:" />
<div id=":r2:" />
</div>,
);

result = shallowRenderer.render(<SomeComponent />);

expect(result).toEqual(
<div>
<div id=":r1:" />
<div id=":r2:" />
</div>,
);
});

it('should work with useSyncExternalStore', () => {
function createExternalStore(initialState) {
const listeners = new Set();
let currentState = initialState;
return {
set(text) {
currentState = text;
listeners.forEach(listener => listener());
},
subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
},
getState() {
return currentState;
},
getSubscriberCount() {
return listeners.size;
},
};
}

const store = createExternalStore('hello');

function SomeComponent() {
const value = React.useSyncExternalStore(store.subscribe, store.getState);
return <div>{value}</div>;
}

const shallowRenderer = createRenderer();
let result = shallowRenderer.render(<SomeComponent />);
expect(result).toEqual(<div>hello</div>);
store.set('goodbye');
result = shallowRenderer.render(<SomeComponent />);
expect(result).toEqual(<div>goodbye</div>);
});
});
20 changes: 9 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4488,7 +4488,7 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.4"

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

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

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

read-pkg-up@^7.0.1:
version "7.0.1"
Expand Down

0 comments on commit bb9f556

Please sign in to comment.