Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/components/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ export interface ProviderProps<
function Provider<A extends Action<string> = UnknownAction, S = unknown>(
providerProps: ProviderProps<A, S>,
) {
if (process.env.NODE_ENV !== 'production') {
// The React Server Components build of React has no effect hooks
if (typeof useIsomorphicLayoutEffect !== 'function') {
throw new Error(
'The React Redux `<Provider>` component requires React hooks that are ' +
'not available in a React Server Component. This usually means you are ' +
'rendering `<Provider>` in a Server Component. Add the `"use client"` ' +
'directive to the top of the file that renders `<Provider>` (or a ' +
'parent that ends up rendering it) so it is treated as a Client ' +
'Component. See https://react.dev/reference/rsc/use-client for more ' +
'information.',
)
}
}

const { children, context, serverState, store } = providerProps

const contextValue = React.useMemo(() => {
Expand Down
31 changes: 31 additions & 0 deletions test/components/Provider-rsc.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as rtl from '@testing-library/react'
import { Provider } from 'react-redux'
import { createStore } from 'redux'

// Simulates the React Server Components build of React, which has no effect hooks
vi.mock('../../src/utils/useIsomorphicLayoutEffect', () => ({
useIsomorphicLayoutEffect: undefined,
}))

// The bundled build inlines `useIsomorphicLayoutEffect`, so there is no module to mock
const describeSource = process.env.TEST_DIST ? describe.skip : describe

describeSource('React', () => {
describe('Provider in a React Server Component environment', () => {
it('throws an actionable error when React effect hooks are unavailable', () => {
const store = createStore(() => ({}))

const spy = vi.spyOn(console, 'error').mockImplementation(() => {})

expect(() =>
rtl.render(
<Provider store={store}>
<div />
</Provider>,
),
).toThrow(/React Server Component/)

spy.mockRestore()
})
})
})
Loading