Skip to content

Commit f1bf253

Browse files
authored
Merge pull request #2085 from reduxjs/feature/9.0-react-is-inline
2 parents 6ca2d66 + fdbd57c commit f1bf253

File tree

6 files changed

+164
-65
lines changed

6 files changed

+164
-65
lines changed

package.json

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@
2828
"import": "./dist/react-redux.alternate-renderers.mjs"
2929
}
3030
},
31-
"sideEffects": "false",
31+
"sideEffects": false,
3232
"files": [
33-
"dist",
34-
"es"
33+
"dist"
3534
],
3635
"scripts": {
3736
"build": "tsup",
@@ -72,7 +71,6 @@
7271
},
7372
"dependencies": {
7473
"@types/use-sync-external-store": "^0.0.3",
75-
"react-is": "^18.0.0",
7674
"use-sync-external-store": "^1.0.0"
7775
},
7876
"devDependencies": {
@@ -87,17 +85,15 @@
8785
"@babel/preset-env": "^7.12.1",
8886
"@babel/preset-typescript": "^7.14.5",
8987
"@microsoft/api-extractor": "^7.18.1",
90-
"@reduxjs/toolkit": "^2.0.0-beta.0",
88+
"@reduxjs/toolkit": "^2.0.0-beta.4",
9189
"@testing-library/jest-dom": "^5.11.5",
9290
"@testing-library/jest-native": "^3.4.3",
9391
"@testing-library/react": "13.0.0",
9492
"@testing-library/react-12": "npm:@testing-library/react@^12",
9593
"@testing-library/react-hooks": "^3.4.2",
9694
"@testing-library/react-native": "^7.1.0",
97-
"@types/object-assign": "^4.0.30",
9895
"@types/react": "^18",
9996
"@types/react-dom": "^18",
100-
"@types/react-is": "^17",
10197
"@types/react-native": "^0.67.4",
10298
"@typescript-eslint/eslint-plugin": "^4.28.0",
10399
"@typescript-eslint/parser": "^4.28.0",

src/components/connect.tsx

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable valid-jsdoc, @typescript-eslint/no-unused-vars */
22
import type { ComponentType } from 'react'
33
import * as React from 'react'
4-
import { isValidElementType, isContextConsumer } from 'react-is'
4+
import { isValidElementType, isContextConsumer } from '../utils/react-is'
55

66
import type { Store } from 'redux'
77

@@ -491,15 +491,14 @@ function connect<
491491
type WrappedComponentProps = TProps &
492492
ConnectPropsMaybeWithoutContext<TProps>
493493

494-
if (
495-
process.env.NODE_ENV !== 'production' &&
496-
!isValidElementType(WrappedComponent)
497-
) {
498-
throw new Error(
499-
`You must pass a component to the function returned by connect. Instead received ${stringifyComponent(
500-
WrappedComponent
501-
)}`
502-
)
494+
if (process.env.NODE_ENV !== 'production') {
495+
const isValid = /*#__PURE__*/ isValidElementType(WrappedComponent)
496+
if (!isValid)
497+
throw new Error(
498+
`You must pass a component to the function returned by connect. Instead received ${stringifyComponent(
499+
WrappedComponent
500+
)}`
501+
)
503502
}
504503

505504
const wrappedComponentName =
@@ -544,12 +543,22 @@ function connect<
544543
const ContextToUse: ReactReduxContextInstance = React.useMemo(() => {
545544
// Users may optionally pass in a custom context instance to use instead of our ReactReduxContext.
546545
// Memoize the check that determines which context instance we should use.
547-
return propsContext &&
548-
propsContext.Consumer &&
549-
// @ts-ignore
550-
isContextConsumer(<propsContext.Consumer />)
551-
? propsContext
552-
: Context
546+
let ResultContext = Context
547+
if (propsContext?.Consumer) {
548+
if (process.env.NODE_ENV !== 'production') {
549+
const isValid = /*#__PURE__*/ isContextConsumer(
550+
// @ts-ignore
551+
<propsContext.Consumer />
552+
)
553+
if (!isValid) {
554+
throw new Error(
555+
'You must pass a valid React context consumer as `props.context`'
556+
)
557+
}
558+
ResultContext = propsContext
559+
}
560+
}
561+
return ResultContext
553562
}, [propsContext, Context])
554563

555564
// Retrieve the store and ancestor subscription via context, if available
@@ -797,10 +806,10 @@ function connect<
797806
const forwarded = _forwarded as ConnectedWrapperComponent
798807
forwarded.displayName = displayName
799808
forwarded.WrappedComponent = WrappedComponent
800-
return hoistStatics(forwarded, WrappedComponent)
809+
return /*#__PURE__*/ hoistStatics(forwarded, WrappedComponent)
801810
}
802811

803-
return hoistStatics(Connect, WrappedComponent)
812+
return /*#__PURE__*/ hoistStatics(Connect, WrappedComponent)
804813
}
805814

806815
return wrapWithConnect

src/utils/hoistStatics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
88
*/
99
import type * as React from 'react'
10-
import { ForwardRef, Memo, isMemo } from 'react-is'
10+
import { ForwardRef, Memo, isMemo } from '../utils/react-is'
1111

1212
const REACT_STATICS = {
1313
childContextTypes: true,

src/utils/react-is.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import type { ElementType, MemoExoticComponent, ReactElement } from 'react'
2+
3+
// Directly ported from:
4+
// https://unpkg.com/browse/[email protected]/cjs/react-is.production.js
5+
// It's very possible this could change in the future, but given that
6+
// we only use these in `connect`, this is a low priority.
7+
8+
const REACT_ELEMENT_TYPE = Symbol.for('react.element')
9+
const REACT_PORTAL_TYPE = Symbol.for('react.portal')
10+
const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment')
11+
const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode')
12+
const REACT_PROFILER_TYPE = Symbol.for('react.profiler')
13+
const REACT_PROVIDER_TYPE = Symbol.for('react.provider')
14+
const REACT_CONTEXT_TYPE = Symbol.for('react.context')
15+
const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context')
16+
const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref')
17+
const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense')
18+
const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list')
19+
const REACT_MEMO_TYPE = Symbol.for('react.memo')
20+
const REACT_LAZY_TYPE = Symbol.for('react.lazy')
21+
const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen')
22+
const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference')
23+
24+
export const ForwardRef = REACT_FORWARD_REF_TYPE
25+
export const Memo = REACT_MEMO_TYPE
26+
27+
export function isValidElementType(type: any): type is ElementType {
28+
if (typeof type === 'string' || typeof type === 'function') {
29+
return true
30+
} // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
31+
32+
if (
33+
type === REACT_FRAGMENT_TYPE ||
34+
type === REACT_PROFILER_TYPE ||
35+
type === REACT_STRICT_MODE_TYPE ||
36+
type === REACT_SUSPENSE_TYPE ||
37+
type === REACT_SUSPENSE_LIST_TYPE ||
38+
type === REACT_OFFSCREEN_TYPE
39+
) {
40+
return true
41+
}
42+
43+
if (typeof type === 'object' && type !== null) {
44+
if (
45+
type.$$typeof === REACT_LAZY_TYPE ||
46+
type.$$typeof === REACT_MEMO_TYPE ||
47+
type.$$typeof === REACT_PROVIDER_TYPE ||
48+
type.$$typeof === REACT_CONTEXT_TYPE ||
49+
type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object
50+
// types supported by any Flight configuration anywhere since
51+
// we don't know which Flight build this will end up being used
52+
// with.
53+
type.$$typeof === REACT_CLIENT_REFERENCE ||
54+
type.getModuleId !== undefined
55+
) {
56+
return true
57+
}
58+
}
59+
60+
return false
61+
}
62+
63+
function typeOf(object: any): symbol | undefined {
64+
if (typeof object === 'object' && object !== null) {
65+
const $$typeof = object.$$typeof
66+
67+
switch ($$typeof) {
68+
case REACT_ELEMENT_TYPE: {
69+
const type = object.type
70+
71+
switch (type) {
72+
case REACT_FRAGMENT_TYPE:
73+
case REACT_PROFILER_TYPE:
74+
case REACT_STRICT_MODE_TYPE:
75+
case REACT_SUSPENSE_TYPE:
76+
case REACT_SUSPENSE_LIST_TYPE:
77+
return type
78+
79+
default: {
80+
const $$typeofType = type && type.$$typeof
81+
82+
switch ($$typeofType) {
83+
case REACT_SERVER_CONTEXT_TYPE:
84+
case REACT_CONTEXT_TYPE:
85+
case REACT_FORWARD_REF_TYPE:
86+
case REACT_LAZY_TYPE:
87+
case REACT_MEMO_TYPE:
88+
case REACT_PROVIDER_TYPE:
89+
return $$typeofType
90+
91+
default:
92+
return $$typeof
93+
}
94+
}
95+
}
96+
}
97+
98+
case REACT_PORTAL_TYPE: {
99+
return $$typeof
100+
}
101+
}
102+
}
103+
104+
return undefined
105+
}
106+
107+
export function isContextConsumer(object: any): object is ReactElement {
108+
return typeOf(object) === REACT_CONTEXT_TYPE
109+
}
110+
111+
export function isMemo(object: any): object is MemoExoticComponent<any> {
112+
return typeOf(object) === REACT_MEMO_TYPE
113+
}

test/typetests/react-redux-types.typetest.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
fetchCount,
3737
} from './counterApp'
3838

39-
import objectAssign from 'object-assign'
39+
const objectAssign = Object.assign
4040

4141
class Counter extends Component<any, any> {
4242
render() {

yarn.lock

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,23 +2419,23 @@ __metadata:
24192419
languageName: node
24202420
linkType: hard
24212421

2422-
"@reduxjs/toolkit@npm:^2.0.0-beta.0":
2423-
version: 2.0.0-beta.0
2424-
resolution: "@reduxjs/toolkit@npm:2.0.0-beta.0"
2422+
"@reduxjs/toolkit@npm:^2.0.0-beta.4":
2423+
version: 2.0.0-beta.4
2424+
resolution: "@reduxjs/toolkit@npm:2.0.0-beta.4"
24252425
dependencies:
24262426
immer: ^10.0.2
2427-
redux: 5.0.0-beta.0
2428-
redux-thunk: 3.0.0-alpha.3
2429-
reselect: ^5.0.0-alpha.2
2427+
redux: ^5.0.0-beta.0
2428+
redux-thunk: ^3.0.0-beta.0
2429+
reselect: ^5.0.0-beta.0
24302430
peerDependencies:
24312431
react: ^16.9.0 || ^17.0.0 || ^18
2432-
react-redux: ^7.2.1 || ^8.0.2
2432+
react-redux: ^7.2.1 || ^8.0.2 || ^9.0.0-beta.0
24332433
peerDependenciesMeta:
24342434
react:
24352435
optional: true
24362436
react-redux:
24372437
optional: true
2438-
checksum: e03ecca1ef61d1073908095cb43215b3f8254c0a81872d44b0f49788ade72bf303bffd43dee57a8f8acebf76fade7e0bfb3d049189aed4467cb98b2e5e7c5b01
2438+
checksum: f7fe690b26840485a0dbc4a367424fc6c96604d8f6cab17ccb216ce1320d9a5c2f81c13d4e93d14095de6b0196ac742bff43b4834494be258ee42559e9dd429c
24392439
languageName: node
24402440
linkType: hard
24412441

@@ -2785,13 +2785,6 @@ __metadata:
27852785
languageName: node
27862786
linkType: hard
27872787

2788-
"@types/object-assign@npm:^4.0.30":
2789-
version: 4.0.30
2790-
resolution: "@types/object-assign@npm:4.0.30"
2791-
checksum: 24e0471ddcd578b7ea72d5174e9cd6b68d78b5fa00f9f48cee38713c0e2886c6c3478c53c04d0508d16deb4370eed71ed0bb1f5b9aaa406e61f07ffed5da1d3b
2792-
languageName: node
2793-
linkType: hard
2794-
27952788
"@types/prettier@npm:^2.1.5":
27962789
version: 2.7.3
27972790
resolution: "@types/prettier@npm:2.7.3"
@@ -2815,15 +2808,6 @@ __metadata:
28152808
languageName: node
28162809
linkType: hard
28172810

2818-
"@types/react-is@npm:^17":
2819-
version: 17.0.3
2820-
resolution: "@types/react-is@npm:17.0.3"
2821-
dependencies:
2822-
"@types/react": "*"
2823-
checksum: 6abb7c47d54f012272650df8a962a28bd82f219291e5ef8b4dfa7fe0bb98ae243b060bf9fbe8ceff6213141794855a006db194b490b00ffd15842ae19d0ce1f0
2824-
languageName: node
2825-
linkType: hard
2826-
28272811
"@types/react-native@npm:^0.67.4":
28282812
version: 0.67.4
28292813
resolution: "@types/react-native@npm:0.67.4"
@@ -9381,17 +9365,15 @@ __metadata:
93819365
"@babel/preset-env": ^7.12.1
93829366
"@babel/preset-typescript": ^7.14.5
93839367
"@microsoft/api-extractor": ^7.18.1
9384-
"@reduxjs/toolkit": ^2.0.0-beta.0
9368+
"@reduxjs/toolkit": ^2.0.0-beta.4
93859369
"@testing-library/jest-dom": ^5.11.5
93869370
"@testing-library/jest-native": ^3.4.3
93879371
"@testing-library/react": 13.0.0
93889372
"@testing-library/react-12": "npm:@testing-library/react@^12"
93899373
"@testing-library/react-hooks": ^3.4.2
93909374
"@testing-library/react-native": ^7.1.0
9391-
"@types/object-assign": ^4.0.30
93929375
"@types/react": ^18
93939376
"@types/react-dom": ^18
9394-
"@types/react-is": ^17
93959377
"@types/react-native": ^0.67.4
93969378
"@types/use-sync-external-store": ^0.0.3
93979379
"@typescript-eslint/eslint-plugin": ^4.28.0
@@ -9412,7 +9394,6 @@ __metadata:
94129394
prettier: ^2.1.2
94139395
react: 18.2.0
94149396
react-dom: 18.2.0
9415-
react-is: ^18.0.0
94169397
react-native: ^0.71.11
94179398
react-test-renderer: 18.0.0
94189399
redux: ^5.0.0-beta.0
@@ -9589,16 +9570,16 @@ __metadata:
95899570
languageName: node
95909571
linkType: hard
95919572

9592-
"redux-thunk@npm:3.0.0-alpha.3":
9593-
version: 3.0.0-alpha.3
9594-
resolution: "redux-thunk@npm:3.0.0-alpha.3"
9573+
"redux-thunk@npm:^3.0.0-beta.0":
9574+
version: 3.0.0-beta.0
9575+
resolution: "redux-thunk@npm:3.0.0-beta.0"
95959576
peerDependencies:
9596-
redux: ^4
9597-
checksum: a5be77887b422b3182ff7fae617ec552cd5f830afb326d83af32a430c3eb439c942a38c3691e5c975119e37787974172dbc0139f7782cbfaeea5c1292fa123ed
9577+
redux: ^4 || ^5.0.0-beta.0
9578+
checksum: 1609e18a9fb56ab7403d760999996b50e136fcf7411ec9d809e9a4afa4187bf0ab545652c05ffbfca2e0397e59e6baf2ae0d35631a30bf8ba20af1205e98e0fe
95989579
languageName: node
95999580
linkType: hard
96009581

9601-
"redux@npm:5.0.0-beta.0, redux@npm:^5.0.0-beta.0":
9582+
"redux@npm:^5.0.0-beta.0":
96029583
version: 5.0.0-beta.0
96039584
resolution: "redux@npm:5.0.0-beta.0"
96049585
checksum: 11df373e219f2f515ee1bda1a19a1ba5de02d8d5c874800ec353179dcd106eddd54432946fd0ab37c47f99f8fe53f820a6404c14da7f039a46022187e9469d2d
@@ -9738,10 +9719,10 @@ __metadata:
97389719
languageName: node
97399720
linkType: hard
97409721

9741-
"reselect@npm:^5.0.0-alpha.2":
9742-
version: 5.0.0-alpha.2
9743-
resolution: "reselect@npm:5.0.0-alpha.2"
9744-
checksum: c47b66999800e1297721cbc4b2464b520fade9823c598d578759c9fba3eb6be03b184e13c20f30820cc18fe2688fc9fb4475f83e59d8f2347aa0d591e465637d
9722+
"reselect@npm:^5.0.0-beta.0":
9723+
version: 5.0.0-beta.0
9724+
resolution: "reselect@npm:5.0.0-beta.0"
9725+
checksum: 462363aa730af93e396ff0d885f88fb8c43572b07f51c2a890d37f27edc3afecd300085916533e336142b3883f8532f35b5b1a2aaa1a70e9909aea48e5d3b98f
97459726
languageName: node
97469727
linkType: hard
97479728

0 commit comments

Comments
 (0)