From 7bdd8ac271965d52cefc999c12e29d6ffbea3ddd Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Mon, 4 Dec 2023 14:30:33 -0500 Subject: [PATCH 1/4] Add an RN-specific bundle and consolidate imports --- package.json | 2 ++ src/alternate-renderers.ts | 2 +- src/components/Context.ts | 2 +- src/components/Provider.tsx | 2 +- src/components/connect.tsx | 2 +- src/hooks/useReduxContext.ts | 2 +- src/hooks/useSelector.ts | 3 +- src/react-native.ts | 28 +++++++++++++++++++ src/utils/react.ts | 6 ++++ src/utils/useIsomorphicLayoutEffect.native.ts | 2 +- src/utils/useIsomorphicLayoutEffect.ts | 2 +- tsup.config.ts | 9 ++++++ 12 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 src/react-native.ts create mode 100644 src/utils/react.ts diff --git a/package.json b/package.json index 45a3a0a2a..087adeb8e 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,14 @@ "bugs": "https://github.com/reduxjs/react-redux/issues", "module": "dist/react-redux.legacy-esm.js", "main": "dist/cjs/index.js", + "react-native": "./dist/react-redux.react-native.mjs", "types": "dist/react-redux.d.ts", "exports": { "./package.json": "./package.json", ".": { "types": "./dist/react-redux.d.ts", "react-server": "./dist/rsc.mjs", + "react-native": "./dist/react-redux.react-native.mjs", "import": "./dist/react-redux.mjs", "default": "./dist/cjs/index.js" }, diff --git a/src/alternate-renderers.ts b/src/alternate-renderers.ts index d08c5add4..88a92f03a 100644 --- a/src/alternate-renderers.ts +++ b/src/alternate-renderers.ts @@ -3,7 +3,7 @@ // Examples include React-Three-Fiber, Ink, etc. // We'll assume they're built with React 18 and thus have `useSyncExternalStore` available. -import * as React from 'react' +import { React } from './utils/react' import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js' import { initializeUseSelector } from './hooks/useSelector' diff --git a/src/components/Context.ts b/src/components/Context.ts index 006942227..66238ed5e 100644 --- a/src/components/Context.ts +++ b/src/components/Context.ts @@ -1,5 +1,5 @@ import type { Context } from 'react' -import * as React from 'react' +import { React } from '../utils/react' import type { Action, Store, UnknownAction } from 'redux' import type { Subscription } from '../utils/Subscription' import type { ProviderProps } from './Provider' diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index e93a94fad..afac66540 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -1,5 +1,5 @@ import type { Context, ReactNode } from 'react' -import * as React from 'react' +import { React } from '../utils/react' import type { Action, Store, UnknownAction } from 'redux' import type { DevModeCheckFrequency } from '../hooks/useSelector' import { createSubscription } from '../utils/Subscription' diff --git a/src/components/connect.tsx b/src/components/connect.tsx index bcec8eec8..769b18bac 100644 --- a/src/components/connect.tsx +++ b/src/components/connect.tsx @@ -1,6 +1,6 @@ /* eslint-disable valid-jsdoc, @typescript-eslint/no-unused-vars */ import type { ComponentType } from 'react' -import * as React from 'react' +import { React } from '../utils/react' import { isValidElementType, isContextConsumer } from '../utils/react-is' import type { Store } from 'redux' diff --git a/src/hooks/useReduxContext.ts b/src/hooks/useReduxContext.ts index fdae9b5b7..86dae5954 100644 --- a/src/hooks/useReduxContext.ts +++ b/src/hooks/useReduxContext.ts @@ -1,4 +1,4 @@ -import * as React from 'react' +import { React } from '../utils/react' import { ReactReduxContext } from '../components/Context' import type { ReactReduxContextValue } from '../components/Context' diff --git a/src/hooks/useSelector.ts b/src/hooks/useSelector.ts index 9f1d7b697..629ead80d 100644 --- a/src/hooks/useSelector.ts +++ b/src/hooks/useSelector.ts @@ -1,4 +1,5 @@ -import * as React from 'react' +//import * as React from 'react' +import { React } from '../utils/react' import type { ReactReduxContextValue } from '../components/Context' import { ReactReduxContext } from '../components/Context' diff --git a/src/react-native.ts b/src/react-native.ts new file mode 100644 index 000000000..27bc27f67 --- /dev/null +++ b/src/react-native.ts @@ -0,0 +1,28 @@ +// The primary entry point assumes we are working with React 18, and thus have +// useSyncExternalStore available. We can import that directly from React itself. +// The useSyncExternalStoreWithSelector has to be imported, but we can use the +// non-shim version. This shaves off the byte size of the shim. + +import { React } from './utils/react' +import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js' + +import { unstable_batchedUpdates as batchInternal } from './utils/reactBatchedUpdates.native' +import { setBatch } from './utils/batch' + +import { initializeUseSelector } from './hooks/useSelector' +import { initializeConnect } from './components/connect' + +initializeUseSelector(useSyncExternalStoreWithSelector) +initializeConnect(React.useSyncExternalStore) + +// Enable batched updates in our subscriptions for use +// with standard React renderers (ReactDOM, React Native) +setBatch(batchInternal) + +// Avoid needing `react-dom` in the final TS types +// by providing a simpler type for `batch` +const batch: (cb: () => void) => void = batchInternal + +export { batch } + +export * from './exports' diff --git a/src/utils/react.ts b/src/utils/react.ts new file mode 100644 index 000000000..b842234a0 --- /dev/null +++ b/src/utils/react.ts @@ -0,0 +1,6 @@ +import * as ReactOriginal from 'react' +import type * as ReactNamespace from 'react' + +export const React = ( + 'default' in ReactOriginal ? ReactOriginal['default'] : ReactOriginal +) as typeof ReactNamespace diff --git a/src/utils/useIsomorphicLayoutEffect.native.ts b/src/utils/useIsomorphicLayoutEffect.native.ts index 80a30f17a..c3b22c296 100644 --- a/src/utils/useIsomorphicLayoutEffect.native.ts +++ b/src/utils/useIsomorphicLayoutEffect.native.ts @@ -1,4 +1,4 @@ -import * as React from 'react' +import { React } from '../utils/react' // Under React Native, we know that we always want to use useLayoutEffect diff --git a/src/utils/useIsomorphicLayoutEffect.ts b/src/utils/useIsomorphicLayoutEffect.ts index 0cb1776f1..329c00e10 100644 --- a/src/utils/useIsomorphicLayoutEffect.ts +++ b/src/utils/useIsomorphicLayoutEffect.ts @@ -1,4 +1,4 @@ -import * as React from 'react' +import { React } from '../utils/react' // React currently throws a warning when using useLayoutEffect on the server. // To get around it, we can conditionally useEffect on the server (no-op) and diff --git a/tsup.config.ts b/tsup.config.ts index 81a61b1c2..95925fd44 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -76,6 +76,15 @@ export default defineConfig((options) => { format: ['esm'], outExtension: () => ({ js: '.mjs' }), }, + // React Native requires a separate entry point for `"react-native"` batch dep + { + ...commonOptions, + entry: { + 'react-redux.react-native': 'src/react-native.ts', + }, + format: ['esm'], + outExtension: () => ({ js: '.mjs' }), + }, // CJS development { ...commonOptions, From c63d190b0ca478fbeef28ee2d655ece7710e0a3b Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Mon, 4 Dec 2023 14:34:32 -0500 Subject: [PATCH 2/4] Remove v2 branch --- .github/workflows/test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ce50c33ef..df51cd4fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -121,10 +121,6 @@ jobs: - name: Clone RTK repo run: git clone https://github.com/reduxjs/redux-toolkit.git ./redux-toolkit - - name: Check out v2.0-integration - working-directory: ./redux-toolkit - run: git checkout v2.0-integration - - name: Check folder contents run: ls -l . From fd2631f86110128d75b8170529ae20398f215249 Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Mon, 4 Dec 2023 15:00:09 -0500 Subject: [PATCH 3/4] Really hack around React export --- src/utils/react.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/utils/react.ts b/src/utils/react.ts index b842234a0..faab8eceb 100644 --- a/src/utils/react.ts +++ b/src/utils/react.ts @@ -1,6 +1,7 @@ import * as ReactOriginal from 'react' import type * as ReactNamespace from 'react' -export const React = ( - 'default' in ReactOriginal ? ReactOriginal['default'] : ReactOriginal -) as typeof ReactNamespace +export const React: typeof ReactNamespace = + // prettier-ignore + // @ts-ignore + 'default' in ReactOriginal ? ReactOriginal['default'] : ReactOriginal as any From e5a558af9c1ddbe2169068dce9fdcad782e84f1b Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Mon, 4 Dec 2023 15:00:18 -0500 Subject: [PATCH 4/4] Update Redux dep --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 087adeb8e..ed1e7d6c0 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "react": "^18.0", "react-dom": "^18.0", "react-native": ">=0.71", - "redux": "^5.0.0-rc" + "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { diff --git a/yarn.lock b/yarn.lock index 38c2859b8..17f8ee656 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9417,7 +9417,7 @@ __metadata: react: ^18.0 react-dom: ^18.0 react-native: ">=0.71" - redux: ^5.0.0-rc + redux: ^5.0.0 peerDependenciesMeta: "@types/react": optional: true