Skip to content

Commit

Permalink
Remove ApiWithInjectedEndpoints references
Browse files Browse the repository at this point in the history
  • Loading branch information
msutkowski committed May 30, 2021
1 parent 80d9f40 commit 05b2e8c
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 106 deletions.
100 changes: 6 additions & 94 deletions docs/rtk-query/usage/code-splitting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
// initialize an empty api service that we'll inject endpoints into later as needed
export const emptySplitApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: () => ({}),
endpoints: () => ({})
})
```

Expand All @@ -36,19 +36,19 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

export const emptySplitApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: () => ({}),
endpoints: () => ({})
})

// file: extendedApi.ts
import { emptySplitApi } from './emptySplitApi'

const extendedApi = emptySplitApi.injectEndpoints({
endpoints: (build) => ({
endpoints: build => ({
example: build.query({
query: () => 'test',
}),
query: () => 'test'
})
}),
overrideExisting: false,
overrideExisting: false
})

export const { useExampleQuery } = extendedApi
Expand All @@ -57,91 +57,3 @@ export const { useExampleQuery } = extendedApi
:::tip
You will get a warning if you inject an endpoint that already exists in development mode when you don't explicitly specify `overrideExisting: true`. You **will not see this in production** and the existing endpoint will just be overriden, so make sure to account for this in your tests.
:::

## Typing a "completely injected" API using `ApiWithInjectedEndpoints`

However, doing this, you will never end up with one "big api definition" that has correct types for all endpoints. Under certain circumstances, that might be useful though. So you can use the `ApiWithInjectedEndpoints` to construct this "full api definition" yourself:

```ts title="Declaring an API using ApiWithInjectedEndpoints"
// file: posts.ts noEmit
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const apiWithPosts = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: () => ({}),
})
// file: post.ts noEmit
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const apiWithPost = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: () => ({}),
})

// file: splitApi.ts
import {
createApi,
fetchBaseQuery,
ApiWithInjectedEndpoints,
} from '@reduxjs/toolkit/query'

// initialize an empty api service that we'll inject endpoints into later as needed
export const emptySplitApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
endpoints: () => ({}),
})

// highlight-start
export const splitApi = emptySplitApi as ApiWithInjectedEndpoints<
typeof emptySplitApi,
[
// These are only type imports, not runtime imports, meaning they're not included in the initial bundle
typeof import('./posts').apiWithPosts,
typeof import('./post').apiWithPost
]
>
// highlight-end
```

Note however, that all endpoints added with `ApiWithInjectedEndpoints` are _optional_ on that definition, meaning that you have to check if they are `undefined` before using them.

A good strategy using this would be to do a check for `undefined` with an _asserting_ function, so you don't have your hooks in a conditional, which would violate the rules of hooks.

```tsx title="Using a type assertion"
function assert(condition: any, msg = 'Generic Assertion'): asserts condition {
if (!condition) {
throw new Error(`Assertion failed: ${msg}`)
}
}

const Post = ({ id }: { id: number }) => {
// highlight-start
assert(
splitApi.endpoints.getPost?.useQuery,
'Endpoint `getPost` not loaded! Did you forget to import it in your current bundle?'
)
const { data, error } = splitApi.endpoints.getPost.useQuery(id)
// highlight-end
return error ? (
<>there was an error</>
) : !data ? (
<>loading</>
) : (
<h1>{data.name}</h1>
)
}
```

## Example

<iframe
src="https://codesandbox.io/embed/concepts-code-splitting-9cll0?fontsize=12&hidenavigation=1&theme=dark&module=%2Fsrc%2Ffeatures%2Fposts%2FPostsManager.tsx"
style={{
width: '100%',
height: '600px',
border: 0,
borderRadius: '4px',
overflow: 'hidden',
}}
title="Concepts Code Splitting"
allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
></iframe>
11 changes: 0 additions & 11 deletions src/query/apiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,3 @@ export type Api<
>
}
>

export type ApiWithInjectedEndpoints<
ApiDefinition extends Api<any, any, any, any>,
Injections extends ApiDefinition extends Api<infer B, any, infer R, infer E>
? [Api<B, any, R, E>, ...Api<B, any, R, E>[]]
: never
> = Omit<ApiDefinition, 'endpoints'> &
Omit<Injections, 'endpoints'> & {
endpoints: ApiDefinition['endpoints'] &
Partial<UnionToIntersection<Injections[number]['endpoints']>>
}
1 change: 0 additions & 1 deletion src/query/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export { QueryStatus } from './core/apiState'
export type {
Api,
ApiWithInjectedEndpoints,
Module,
ApiModules,
} from './apiTypes'
Expand Down

0 comments on commit 05b2e8c

Please sign in to comment.