Skip to content

Commit

Permalink
Merge pull request #3855 from reduxjs/nested-apiprovider
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson committed Nov 8, 2023
2 parents 759581f + 9ef5ff9 commit 94fca95
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
6 changes: 4 additions & 2 deletions errors.json
Expand Up @@ -31,5 +31,7 @@
"29": "`builder.addCase` cannot be called with an empty action type",
"30": "`builder.addCase` cannot be called with two reducers for the same action type",
"31": "\"middleware\" field must be a callback",
"32": "When using custom hooks for context, all hooks need to be provided: .\\nHook was either not provided or not a function."
}
"32": "When using custom hooks for context, all hooks need to be provided: .\\nHook was either not provided or not a function.",
"33": "Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.",
"34": "selectSlice returned undefined for an uninjected slice reducer"
}
12 changes: 10 additions & 2 deletions packages/toolkit/src/query/react/ApiProvider.tsx
@@ -1,9 +1,10 @@
import { configureStore } from '@reduxjs/toolkit'
import type { Context } from 'react'
import { useContext } from 'react'
import { useEffect } from 'react'
import React from 'react'
import type { ReactReduxContextValue } from 'react-redux'
import { Provider } from 'react-redux'
import { Provider, ReactReduxContext } from 'react-redux'
import { setupListeners } from '@reduxjs/toolkit/query'
import type { Api } from '@reduxjs/toolkit/query'

Expand Down Expand Up @@ -37,6 +38,13 @@ export function ApiProvider<A extends Api<any, {}, any, any>>(props: {
setupListeners?: Parameters<typeof setupListeners>[1] | false
context?: Context<ReactReduxContextValue>
}) {
const context = props.context || ReactReduxContext
const existingContext = useContext(context)
if (existingContext) {
throw new Error(
'Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.'
)
}
const [store] = React.useState(() =>
configureStore({
reducer: {
Expand All @@ -55,7 +63,7 @@ export function ApiProvider<A extends Api<any, {}, any, any>>(props: {
)

return (
<Provider store={store} context={props.context}>
<Provider store={store} context={context}>
{props.children}
</Provider>
)
Expand Down
13 changes: 13 additions & 0 deletions packages/toolkit/src/query/tests/apiProvider.test.tsx
Expand Up @@ -2,6 +2,8 @@ import * as React from 'react'
import { createApi, ApiProvider } from '@reduxjs/toolkit/query/react'
import { fireEvent, render, waitFor } from '@testing-library/react'
import { waitMs } from './helpers'
import { Provider } from 'react-redux'
import { configureStore } from '@reduxjs/toolkit'

const api = createApi({
baseQuery: async (arg: any) => {
Expand Down Expand Up @@ -57,4 +59,15 @@ describe('ApiProvider', () => {
// Being that nothing has changed in the args, this should never fire.
expect(getByTestId('isFetching').textContent).toBe('false')
})
test('ApiProvider throws if nested inside a Redux context', () => {
expect(() =>
render(
<Provider store={configureStore({ reducer: () => null })}>
<ApiProvider api={api}>child</ApiProvider>
</Provider>
)
).toThrowErrorMatchingInlineSnapshot(
'"Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup."'
)
})
})

0 comments on commit 94fca95

Please sign in to comment.