Skip to content

Commit

Permalink
Merge pull request #4663 from aryaemami59/fix-docs
Browse files Browse the repository at this point in the history
Add `withTypes` to examples in docs
  • Loading branch information
EskiMojo14 committed Jan 12, 2024
2 parents 2008919 + e4afb5e commit fca9009
Show file tree
Hide file tree
Showing 10 changed files with 707 additions and 735 deletions.
6 changes: 3 additions & 3 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "docs",
"devDependencies": {
"@reduxjs/toolkit": "^1.9.0",
"@testing-library/react": "^13.4.0",
"@reduxjs/toolkit": "^2.0.1",
"@testing-library/react": "^14.1.2",
"msw": "^2.0.0",
"react": "^18.2.0",
"react-redux": "^8.0.5"
"react-redux": "^9.1.0"
}
}
8 changes: 4 additions & 4 deletions docs/tutorials/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ While it's possible to import the `RootState` and `AppDispatch` types into each
Since these are actual variables, not types, it's important to define them in a separate file such as `app/hooks.ts`, not the store setup file. This allows you to import them into any component file that needs to use the hooks, and avoids potential circular import dependency issues.
```ts title="app/hooks.ts"
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'

// highlight-start
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
// highlight-end
```

Expand Down
29 changes: 25 additions & 4 deletions docs/usage/UsageWithTypescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,36 @@ While it's possible to import the `RootState` and `AppDispatch` types into each
Since these are actual variables, not types, it's important to define them in a separate file such as `app/hooks.ts`, not the store setup file. This allows you to import them into any component file that needs to use the hooks, and avoids potential circular import dependency issues.
#### `.withTypes()`
Previously, the approach for "pre-typing" hooks with your app setting was a little varied. The result would look something like the snippet below:
```ts title="app/hooks.ts"
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
import type { TypedUseSelectorHook } from 'react-redux'
import { useDispatch, useSelector, useStore } from 'react-redux'
import type { AppDispatch, AppStore, RootState } from './store'

// highlight-start
// Use throughout your app instead of plain `useDispatch` and `useSelector`
type DispatchFunc = () => AppDispatch
export const useAppDispatch: DispatchFunc = useDispatch
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppStore: () => AppStore = useStore
// highlight-end
```

React Redux v9.1.0 adds a new `.withTypes` method to each of these hooks, analogous to the [`.withTypes`](https://redux-toolkit.js.org/usage/usage-with-typescript#defining-a-pre-typed-createasyncthunk) method found on Redux Toolkit's `createAsyncThunk`.

The setup now becomes:

```ts title="app/hooks.ts"
import { useDispatch, useSelector, useStore } from 'react-redux'
import type { AppDispatch, AppStore, RootState } from './store'

// highlight-start
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
export const useAppStore = useStore.withTypes<AppStore>()
// highlight-end
```

Expand Down
50 changes: 29 additions & 21 deletions docs/usage/WritingTests.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,12 @@ export type RootState = ReturnType<typeof rootReducer>
export type AppStore = ReturnType<typeof setupStore>
export type AppDispatch = AppStore['dispatch']
// file: app/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
```

```tsx title="features/users/UserDisplay.tsx"
Expand All @@ -219,11 +220,11 @@ export type RootState = ReturnType<typeof rootReducer>
export type AppStore = ReturnType<typeof setupStore>
export type AppDispatch = AppStore['dispatch']
// file: app/hooks.ts noEmit
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
// file: features/users/userSlice.ts noEmit
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { userAPI } from './userAPI'
Expand Down Expand Up @@ -337,6 +338,7 @@ import { configureStore } from '@reduxjs/toolkit'
import { Provider } from 'react-redux'

import type { AppStore, RootState } from '../app/store'
import { setupStore } from '../app/store'
// As a basic setup, import your same slice reducers
import userReducer from '../features/users/userSlice'

Expand All @@ -349,19 +351,24 @@ interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {

export function renderWithProviders(
ui: React.ReactElement,
{
extendedRenderOptions: ExtendedRenderOptions = {},
) {
const {
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = configureStore({ reducer: { user: userReducer }, preloadedState }),
store = setupStore(preloadedState),
...renderOptions
}: ExtendedRenderOptions = {}
) {
function Wrapper({ children }: PropsWithChildren<{}>): JSX.Element {
return <Provider store={store}>{children}</Provider>
}
} = extendedRenderOptions

const Wrapper = ({ children }: PropsWithChildren) => (
<Provider store={store}>{children}</Provider>
)

// Return an object with the store and all of RTL's query functions
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }
return {
store,
...render(ui, { wrapper: Wrapper, ...renderOptions }),
}
}
```

Expand Down Expand Up @@ -533,10 +540,11 @@ export function renderWithProviders(
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }
}
// file: app/hooks.tsx noEmit
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
// file: features/users/UserDisplay.tsx noEmit
import React from 'react'
import { useAppDispatch, useAppSelector } from '../../app/hooks'
Expand Down Expand Up @@ -719,7 +727,7 @@ export default todosSlice.reducer
import reducer, { todoAdded, Todo } from './todosSlice'

test('should return the initial state', () => {
expect(reducer(undefined, { type: undefined })).toEqual([
expect(reducer(undefined, { type: 'unknown' })).toEqual([
{ text: 'Use Redux', completed: false, id: 0 }
])
})
Expand Down
8 changes: 4 additions & 4 deletions docs/usage/migrating-to-modern-redux.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1105,13 +1105,13 @@ Per [our standard TypeScript setup and usage guidelines](../tutorials/typescript
First, set up the hooks:

```ts no-transpile title="src/app/hooks.ts"
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'

// highlight-start
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
// highlight-end
```

Expand Down
18 changes: 8 additions & 10 deletions docs/usage/nextjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,13 @@ export type AppDispatch = AppStore['dispatch']

// file: lib/hooks.ts
import { useDispatch, useSelector, useStore } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch, AppStore } from './store'
import type { AppDispatch, AppStore, RootState } from './store'

// highlight-start
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppStore: () => AppStore = useStore
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
export const useAppStore = useStore.withTypes<AppStore>()
// highlight-end
```

Expand Down Expand Up @@ -330,14 +329,13 @@ export type AppDispatch = AppStore['dispatch']

// file: lib/hooks.ts noEmit
import { useDispatch, useSelector, useStore } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch, AppStore } from './store'
import type { AppDispatch, AppStore, RootState } from './store'

// highlight-start
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppStore: () => AppStore = useStore
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
export const useAppStore = useStore.withTypes<AppStore>()
// highlight-end

/* prettier-ignore */
Expand Down

0 comments on commit fca9009

Please sign in to comment.