Skip to content

Commit 034bdec

Browse files
committed
Merge branch 'master' into feature/v1.6-integration
2 parents 17d4629 + 4ad8be6 commit 034bdec

File tree

12 files changed

+64
-35
lines changed

12 files changed

+64
-35
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [phryneas]

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ The recommended way to start new apps with React and Redux Toolkit is by using t
1818
npx create-react-app my-app --template redux
1919
```
2020

21+
Or if you are a TypeScript user, use [cra-template-redux-typescript](https://github.com/reduxjs/cra-template-redux-typescript), which is based on that template
22+
23+
```sh
24+
npx create-react-app my-app --template redux-typescript
25+
```
26+
27+
2128
### An Existing App
2229

2330
Redux Toolkit is available as a package on NPM for use with a module bundler or in a Node application:

docs/api/createEntityAdapter.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ The primary content of an entity adapter is a set of generated reducer functions
208208
- `setAll`: accepts an array of entities or an object in the shape of `Record<EntityId, T>`, and replaces the existing entity contents with the values in the array.
209209
- `removeOne`: accepts a single entity ID value, and removes the entity with that ID if it exists.
210210
- `removeMany`: accepts an array of entity ID values, and removes each entity with those IDs if they exist.
211+
- `removeAll`: removes all entities from the entity state object.
211212
- `updateOne`: accepts an "update object" containing an entity ID and an object containing one or more new field values to update inside a `changes` field, and performs a shallow update on the corresponding entity.
212213
- `updateMany`: accepts an array of update objects, and performs shallow updates on all corresponding entities.
213214
- `upsertOne`: accepts a single entity. If an entity with that ID exists, it will perform a shallow update and the specified fields will be merged into the existing entity, with any matching fields overwriting the existing values. If the entity does not exist, it will be added.

docs/api/serializabilityMiddleware.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ interface SerializableStateInvariantMiddlewareOptions {
5555
* Defaults to 32ms.
5656
*/
5757
warnAfter?: number
58+
59+
/**
60+
* Opt out of checking state, but continue checking actions
61+
*/
62+
ignoreState?: boolean
5863
}
5964
```
6065

docs/introduction/getting-started.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ Redux Toolkit is available as a package on NPM for use with a module bundler or
4949
```bash
5050
# NPM
5151
npm install @reduxjs/toolkit
52+
```
53+
54+
or
5255

56+
```bash
5357
# Yarn
5458
yarn add @reduxjs/toolkit
5559
```

docs/tutorials/quick-start.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,9 @@ export default configureStore({
143143
Now we can use the React-Redux hooks to let React components interact with the Redux store. We can read data from the store with `useSelector`, and dispatch actions using `useDispatch`. Create a `src/features/counter/Counter.js` file with a `<Counter>` component inside, then import that component into `App.js` and render it inside of `<App>`.
144144

145145
```jsx title="features/counter/Counter.js"
146-
import React, { useState } from 'react'
146+
import React from 'react'
147147
import { useSelector, useDispatch } from 'react-redux'
148148
import { decrement, increment } from './counterSlice'
149-
import styles from './Counter.module.css'
150149

151150
export function Counter() {
152151
const count = useSelector((state) => state.counter.value)

docs/tutorials/typescript.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Since those are types, it's safe to export them directly from your store setup f
4949
import { configureStore } from '@reduxjs/toolkit'
5050
// ...
5151

52-
const store = configureStore({
52+
export const store = configureStore({
5353
reducer: {
5454
posts: postsReducer,
5555
comments: commentsReducer,
@@ -67,7 +67,7 @@ export type AppDispatch = typeof store.dispatch
6767
6868
### Define Typed Hooks
6969
70-
While it's possible to import the `RootState` and `AppDispatch` types into each component, it's **better to create typed versions of the `useDispatch` and `useSelector` hooks for usage in your application**. . This is important for a couple reasons:
70+
While it's possible to import the `RootState` and `AppDispatch` types into each component, it's **better to create typed versions of the `useDispatch` and `useSelector` hooks for usage in your application**. This is important for a couple reasons:
7171
7272
- For `useSelector`, it saves you the need to type `(state: RootState)` every time
7373
- For `useDispatch`, the default `Dispatch` type does not know about thunks. In order to correctly dispatch thunks, you need to use the specific customized `AppDispatch` type from the store that includes the thunk middleware types, and use that with `useDispatch`. Adding a pre-typed `useDispatch` hook keeps you from forgetting to import `AppDispatch` where it's needed.

docs/usage/usage-guide.md

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Every Redux app needs to configure and create a Redux store. This usually involv
2626
- Importing or creating the root reducer function
2727
- Setting up middleware, likely including at least one middleware to handle asynchronous logic
2828
- Configuring the [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension)
29-
- Possibly altering some of the logic based on whether the application is being built for development or production.
29+
- Possibly altering some of the logic based on whether the application is being built for development or production
3030

3131
### Manual Store Setup
3232

@@ -68,7 +68,7 @@ This example is readable, but the process isn't always straightforward:
6868

6969
`configureStore` helps with those issues by:
7070

71-
- Having an options object with "named" parameters, which can be easier to read.
71+
- Having an options object with "named" parameters, which can be easier to read
7272
- Letting you provide arrays of middleware and enhancers you want to add to the store, and calling `applyMiddleware` and `compose` for you automatically
7373
- Enabling the Redux DevTools Extension automatically
7474

@@ -95,6 +95,8 @@ export default store
9595
You can also pass an object full of ["slice reducers"](https://redux.js.org/recipes/structuring-reducers/splitting-reducer-logic), and `configureStore` will call [`combineReducers`](https://redux.js.org/api/combinereducers) for you:
9696

9797
```js
98+
import { configureStore } from '@reduxjs/toolkit'
99+
// highlight-start
98100
import usersReducer from './usersReducer'
99101
import postsReducer from './postsReducer'
100102

@@ -104,6 +106,9 @@ const store = configureStore({
104106
posts: postsReducer,
105107
},
106108
})
109+
// highlight-end
110+
111+
export default store
107112
```
108113

109114
Note that this only works for one level of reducers. If you want to nest reducers, you'll need to call `combineReducers` yourself to handle the nesting.
@@ -141,7 +146,7 @@ If you provide the `middleware` argument, `configureStore` will only use whateve
141146
[Reducers](https://redux.js.org/basics/reducers) are the most important Redux concept. A typical reducer function needs to:
142147

143148
- Look at the `type` field of the action object to see how it should respond
144-
- Update its state immutably, by making copies of the parts of the state that need to change and only modifying those copies.
149+
- Update its state immutably, by making copies of the parts of the state that need to change and only modifying those copies
145150

146151
While you can [use any conditional logic you want](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/#switch-statements) in a reducer, the most common approach is a `switch` statement, because it's a straightforward way to handle multiple possible values for a single field. However, many people don't like switch statements. The Redux docs show an example of [writing a function that acts as a lookup table based on action types](https://redux.js.org/recipes/reducing-boilerplate#generating-reducers), but leave it up to users to customize that function themselves.
147152

@@ -382,8 +387,8 @@ export default function postsReducer(state = initialState, action) {
382387

383388
The only truly necessary part here is the reducer itself. Consider the other parts:
384389

385-
- We could have written the action types as inline strings in both places.
386-
- The action creators are good, but they're not _required_ to use Redux - a component could skip supplying a `mapDispatch` argument to `connect`, and just call `this.props.dispatch({type : "CREATE_POST", payload : {id : 123, title : "Hello World"}})` itself.
390+
- We could have written the action types as inline strings in both places
391+
- The action creators are good, but they're not _required_ to use Redux - a component could skip supplying a `mapDispatch` argument to `connect`, and just call `this.props.dispatch({type : "CREATE_POST", payload : {id : 123, title : "Hello World"}})` itself
387392
- The only reason we're even writing multiple files is because it's common to separate code by what it does
388393

389394
The ["ducks" file structure](https://github.com/erikras/ducks-modular-redux) proposes putting all of your Redux-related logic for a given slice into a single file, like this:
@@ -479,23 +484,6 @@ console.log(createPost({ id: 123, title: 'Hello World' }))
479484

480485
`createSlice` looked at all of the functions that were defined in the `reducers` field, and for every "case reducer" function provided, generates an action creator that uses the name of the reducer as the action type itself. So, the `createPost` reducer became an action type of `"posts/createPost"`, and the `createPost()` action creator will return an action with that type.
481486

482-
```js
483-
const postsSlice = createSlice({
484-
name: 'posts',
485-
initialState: [],
486-
reducers: {
487-
createPost(state, action) {},
488-
updatePost(state, action) {},
489-
deletePost(state, action) {},
490-
},
491-
})
492-
493-
const { createPost } = postsSlice.actions
494-
495-
console.log(createPost({ id: 123, title: 'Hello World' }))
496-
// {type : "posts/createPost", payload : {id : 123, title : "Hello World"}}
497-
```
498-
499487
### Exporting and Using Slices
500488

501489
Most of the time, you'll want to define a slice, and export its action creators and reducers. The recommended way to do this is using ES6 destructuring and export syntax:
@@ -613,7 +601,7 @@ const fetchUsers = () => async (dispatch) => {
613601

614602
Data fetching logic for Redux typically follows a predictable pattern:
615603

616-
- A "start" action is dispatched before the request, to indicate that the request is in progress. This may be used to track loading state to allow skipping duplicate requests or show loading indicators in the UI.
604+
- A "start" action is dispatched before the request to indicate that the request is in progress. This may be used to track loading state, to allow skipping duplicate requests, or show loading indicators in the UI.
617605
- The async request is made
618606
- Depending on the request result, the async logic dispatches either a "success" action containing the result data, or a "failure" action containing error details. The reducer logic clears the loading state in both cases, and either processes the result data from the success case, or stores the error value for potential display.
619607

@@ -1034,7 +1022,7 @@ One of the core usage principles for Redux is that [you should not put non-seria
10341022

10351023
However, like most rules, there are exceptions. There may be occasions when you have to deal with actions that need to accept non-serializable data. This should be done very rarely and only if necessary, and these non-serializable payloads shouldn't ever make it into your application state through a reducer.
10361024

1037-
The [serializability dev check middleware](../api/getDefaultMiddleware.mdx) will automatically warn anytime it detects non-serializable values in your actions or state. We encourage you to leave this middleware active to help avoid accidentally making mistakes. However, if you _do_ need to turnoff those warnings, you can customize the middleware by configuring it to ignore specific action types, or fields in actions and state:
1025+
The [serializability dev check middleware](../api/serializabilityMiddleware.mdx) will automatically warn anytime it detects non-serializable values in your actions or state. We encourage you to leave this middleware active to help avoid accidentally making mistakes. However, if you _do_ need to turnoff those warnings, you can customize the middleware by configuring it to ignore specific action types, or fields in actions and state:
10381026

10391027
```js
10401028
configureStore({

docs/usage/usage-with-typescript.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ The basics of using `configureStore` are shown in [TypeScript Quick Start tutori
3838
The easiest way of getting the `State` type is to define the root reducer in advance and extract its `ReturnType`.
3939
It is recommend to give the type a different name like `RootState` to prevent confusion, as the type name `State` is usually overused.
4040

41-
```typescript {3}
41+
```typescript
4242
import { combineReducers } from '@reduxjs/toolkit'
4343
const rootReducer = combineReducers({})
44+
// highlight-start
4445
export type RootState = ReturnType<typeof rootReducer>
46+
// highlight-end
4547
```
4648
4749
Alternatively, if you choose to not create a `rootReducer` yourself and instead pass the slice reducers directly to `configureStore()`, you need to slightly modify the typing to correctly infer the root reducer:
@@ -56,13 +58,15 @@ const store = configureStore({
5658
},
5759
})
5860
export type RootState = ReturnType<typeof store.getState>
61+
62+
export default store
5963
```
6064

6165
### Getting the `Dispatch` type
6266

6367
If you want to get the `Dispatch` type from your store, you can extract it after creating the store. It is recommended to give the type a different name like `AppDispatch` to prevent confusion, as the type name `Dispatch` is usually overused. You may also find it to be more convenient to export a hook like `useAppDispatch` shown below, then using it wherever you'd call `useDispatch`.
6468

65-
```typescript {6}
69+
```typescript
6670
import { configureStore } from '@reduxjs/toolkit'
6771
import { useDispatch } from 'react-redux'
6872
import rootReducer from './rootReducer'
@@ -71,8 +75,12 @@ const store = configureStore({
7175
reducer: rootReducer,
7276
})
7377

78+
// highlight-start
7479
export type AppDispatch = typeof store.dispatch
7580
export const useAppDispatch = () => useDispatch<AppDispatch>() // Export a hook that can be reused to resolve types
81+
// highlight-end
82+
83+
export default store
7684
```
7785

7886
### Correct typings for the `Dispatch` type
@@ -83,17 +91,18 @@ As TypeScript often widens array types when combining arrays using the spread op
8391

8492
Also, we suggest using the callback notation for the `middleware` option to get a correctly pre-typed version of `getDefaultMiddleware` that does not require you to specify any generics by hand.
8593

86-
```ts {10-20}
94+
```ts
8795
import { configureStore } from '@reduxjs/toolkit'
8896
import additionalMiddleware from 'additional-middleware'
8997
import logger from 'redux-logger'
9098
// @ts-ignore
9199
import untypedMiddleware from 'untyped-middleware'
92100
import rootReducer from './rootReducer'
93101

94-
type RootState = ReturnType<typeof rootReducer>
102+
export type RootState = ReturnType<typeof rootReducer>
95103
const store = configureStore({
96104
reducer: rootReducer,
105+
// highlight-start
97106
middleware: (getDefaultMiddleware) =>
98107
getDefaultMiddleware()
99108
.prepend(
@@ -107,9 +116,12 @@ const store = configureStore({
107116
)
108117
// prepend and concat calls can be chained
109118
.concat(logger),
119+
// highlight-end
110120
})
111121

112-
type AppDispatch = typeof store.dispatch
122+
export type AppDispatch = typeof store.dispatch
123+
124+
export default store
113125
```
114126

115127
#### Using `MiddlewareArray` without `getDefaultMiddleware`

etc/redux-toolkit.api.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ export class MiddlewareArray<Middlewares extends Middleware<any, any>> extends A
398398
prepend<AdditionalMiddlewares extends ReadonlyArray<Middleware<any, any>>>(...items: AdditionalMiddlewares): MiddlewareArray<AdditionalMiddlewares[number] | Middlewares>;
399399
}
400400

401+
// @public
402+
export const miniSerializeError: (value: any) => SerializedError;
403+
401404
// @public (undocumented)
402405
export let nanoid: (size?: number) => string;
403406

0 commit comments

Comments
 (0)